Mongodb 中的汇总更新

Update on Aggregate in Mongodb

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

文档:

"_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);
});

我尝试使用 $set 但没有成功,因为整个邀请数组被替换为“Accepted = 1” 如何使用特定的“ID”切换文档的“Accepted”字段。

Invitation.$.Accepted

位置运算符不适用于包含数组的字段,因此无法迭代到 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);
    }

为此使用位置更新运算符: 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
    }
);

注意:您不需要聚合步骤,因为它实际上什么都不做。

我真的不认为即使作为馈线查询聚合框架也是在这里使用的正确操作。您所做的只是 "denormalizing" 数组作为单独的文档。真的应该没有必要。只需获取文档即可:

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 but you probably want async.eachLimit to control the looping. The matching of the element comes from the positional $ 运算符,对应于查询中匹配的数组元素。

它只是 JavaScript 代码,所以只需 "toggle" 带有 !invite.accepted 的值即可将其取反。为了获得额外的乐趣,return "results" 数组通过从 .findOneAndUpdate().

推送修改后的文档