Mongodb中的聚合更新 [英] Update on Aggregate in Mongodb

查看:216
本文介绍了Mongodb中的聚合更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

i am trying to toggle a boolean value inside a object, which is a subdocument, i am having hard time to update a particular object within an array.

文件:

"_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但它没有成功,整个邀请数组被'取代已接受= 1 '
如何使用特定的 ID 切换文档的已接受字段。

i tried using $set but it didnt worked out as whole Invitation array got replaced with 'Accepted = 1' How can i toggle 'Accepted' field of the document with particular 'ID'.

Invitation.$.Accepted

位置运算符不适用于包含数组的字段,因此无法迭代到接受字段

Positional operator doesnot apply to field containing array so can't iterate to Accepted field

编辑:

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,首先抛出错误async这里是错误:

The control is not getting inside second async.each, error is thrown on first async here is the error:

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


推荐答案

我真的不认为即使作为馈线查询,聚合框架也是在此使用的正确操作。您所做的只是将数组非规范化为单个文档。真的应该没有必要。只需获取文档:

I really don't think that even as a feeder query the aggregation framework is the right operation to use here. All you are doing is "denormalizing" the array as individual documents. There really should be no need. Just fetch the document instead:

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(),然后异步调用就完成了。

So there is no problem iterating the list of documents in a response for what you are doing, it's just that you also want to iterate the array members as well. The catch is when issuing any kind of .update() that you need to be aware then the asynchronous call is complete.

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

So I'm using async.each but you probably want async.eachLimit to control the looping. The matching of the element comes from the positional $ operator, corresponding to the matched array element in the query.

这只是JavaScript代码,所以只需用切换值!invite.accepted 将反转它。为了更好玩,请通过从 .findOneAndUpdate()

It's just JavaScript code, so simply "toggle" the value with !invite.accepted which will inverse it. For additional fun, return the "results" array by pushing the modified document from .findOneAndUpdate().

这篇关于Mongodb中的聚合更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆