2015-01-15 38 views
3

我想切换一个对象内的布尔值,这是一个子文档,我很难更新数组中的特定对象。在Mongodb Aggregate的更新

文献:

"_id" : ObjectId("54afaabd88694dc019d3b628") 
"Invitation" : [ 
    { 
     "__v" : 0, 
     "ID" : ObjectId("54af6ce091324fd00f97a15f"), 
     "__t" : "USER", 
     "_id" : ObjectId("54b4ceb50fc380001bea1752"), 
     "Accepted" : false 
    }, 
    { 
     "__v" : 0, 
     "ID" : ObjectId("54afac5412f5fdcc007a5c4d"), 
     "__t" : "USER", 
     "_id" : ObjectId("54b4cebe0fc380001bea1753"), 
     "Accepted" : false 
    } 
], 

控制器:

User.aggregate([{$match: {_id: ObjectId(54afaabd88694dc019d3b628)}},{$unwind: '$Invitation'},{$project: {_id: '$_id',Invitation: '$Invitation'}}],function(err,results){ 

    function updateInvitation(_id){ 

       var query = {'_id': _id, 'Invitation.ID': ObjectId("54af6ce091324fd00f97a15f")}; 
       var operator = {$inc: {'Invitation.Accepted': 1}}; 
       User.update(query,operator,{multi:true},function(err,updated){ 
        if(err){ 
         console.log(err); 
        } 
        console.log('updating'+updated); 
       }); 
      } 
      res.jsonp(results); 
      updateInvitation(results[0]._id); 
}); 

我试图使用$设置,但它没有制定出整个邀请阵列得到了与 '接受= 1' 取代 如何切换'接受'文档的字段NT特别是'ID'。

Invitation.$.Accepted 

阵地操作者不列入适用于该字段包含阵列所以不能重复,以接受字段

编辑:

User.find({_id: req.user._id},'Invitation',function(err,docs){ 
    if(err){ 
     console.log(err); 
    } 
    console.log(docs); 
    var results = []; 
    async.each(docs,function(doc,err) { 
     if(err){ 
      console.log('error'+ err); 
     } 
     async.each(docs.Invitation,function(invite,callback) { 
console.log('second async'); 
      User.update(
       { '_id': doc._id, 'Invitation._id': invite._id }, 
       { '$set': {'Invitation.$.Accepted': !invite.Accepted}}, 
       function(err,doc) { 
        results.push(doc); 
        console.log('updated'+doc); 
        callback(err); 
       } 
      ); 
     }); 
    },function(err) { 
     if (err) 
      console.log(err); 
     console.log(results); 
    }); 

}); 

控制没有第二async.each内进入,错误是在第一次异步抛出这里是错误:

error-function() { 
     if (called) throw new Error("Callback was already called."); 
     called = true; 
     fn.apply(root, arguments); 
    } 

回答

1

我真的不认为,即使作为饲养者查询聚合框架是正确的操作在这里使用。您所做的只是将数组“非规范化”为单个文档。真的应该没有必要。只需提取文档,而不是:

var query = {}; // whatever criteria 

Users.find(query,"Invitation",function(err,docs) { 
    if (err) { 
     console.log(err); 

    var results = [];   

    async.each(docs,function(doc,callback) { 
     async.each(docs.Invitation,function(invite,callback) { 
      Users.findOneAndUpdate(
       { "_id": doc._id, "Invitation._id": invite._id }, 
       { "$set": { "Invitation.$.Accepted": !invite.Accepted } }, 
       function(err,doc) { 
        results.push(doc); 
        callback(err); 
       } 
      ); 
     },callback); 
    },function(err) { 
     if (err) 
      console.log(err); 

     console.log(results); 
    });  

}); 

因此,有迭代为你在做什么回应的文件列表中没有问题,只是你还想要遍历数组成员。当你发布任何类型的.update()时,你需要知道异步调用是否完成。

所以我使用async.each但你可能想要async.eachLimit来控制循环。元素的匹配来自positional $运算符,对应于查询中匹配的数组元素。

这只是JavaScript代码,所以只需将其与!invite.accepted“切换”即可反转。为了获得更多乐趣,请从.findOneAndUpdate()推送修改后的文档返回“结果”数组。

+0

谢谢你的回答,但我在async.each https:// github上得到这个错误。com/caolan/async/issues/610 –

+0

@shaileshshekhawat这个问题是关于一个未定义的数组对象?那么哪个数组对象在这里没有定义? '.find()'的结果应该是返回文档或者查询是错误的。如果内部的“Invitation”数组未定义,那么您可以在提交给async.each之前测试该值。 –

+0

@ NeilLunn -query查询'.find()'返回已经定义的邀请数组,我在'console.log(docs)'上测试过它,但仍然出现这个奇怪的错误 –

0

使用位置更新操作此: http://docs.mongodb.org/manual/reference/operator/update/positional/

User.update(
    { 
     "_id": ObjectId("54afaabd88694dc019d3b628"), 
     "Invitation": {"$elemMatch": {"ID" : ObjectId("54af6ce091324fd00f97a15f"), "Accepted":false}} 
    }, 
    { 
     "$set" : { 
      "Invitation.$.Accepted" : true 
     } 
    },{multi:false, upsert:false, safe:true}, function (err, numAffectedDocuments){ 
     // TODO 
    } 
); 

注意:你不需要聚集步骤,因为它实际上什么也不做。

+0

我已经尝试过使用位置运算符,但得到了这个错误 '不能应用包含数组' –

+0

@shaileshshekhawat的位置运算符字段,因为要更新的字段也需要在查询中。我编辑了答案中的代码以纠正错误。 – joao