在mongodb中更新数组中的所有元素

3

我有一个类似于mongodb文档的数据:

{
    "name" : "JohnDoe",
    "adds" : [
        {
            "status" : "PENDING",
            "date" : "2015-09-23"
        },
        {
            "status" : "PENDING",
            "date" : "2015-10-01"
        }
    ]
}

我想更新所有元素数组,例如:

collection.update({'name':'JohnDoe'}, {'$set':{'adds.status':'APPROVED'}}).

如何做到这一点?

编辑:大多数解决方案建议使用定位操作符选择数组元素,然后使用操作符更新该元素。但在我的情况下,我必须更新数组中的每个元素。


@sheilak 在那篇帖子中,用户可以选择单个数组元素,然后使用位置操作符进行更新。但是我必须更新数组中的每个元素。 - Manish Gupta
那个问题的答案解释了你不能在一个更新中对数组中的所有项执行$set操作。被接受的答案链接到一个关于这个问题的开放JIRA票据。还有多个解决方法发布。 - sheilak
1个回答

3

如前所述,主要问题在于使用位置操作符更新多个元素时的更新问题,这一点已经记录在这个长期存在的问题中:http://jira.mongodb.org/browse/SERVER-1243

因此,基本情况是没有单个执行可以完成此操作,因此为了处理多个数组元素,您需要某种确定需要更新多少个元素并为每个元素处理一个更新语句的方法。

简化此过程通常使用Bulk Operations来处理最终成为“多个”更新操作的单个请求和响应到服务器:

var bulk = db.collection.initializeOrderedBulkOp(),
    count = 0;

db.collection.find({ "name": "John Doe", "adds.status": "PENDING" }).forEach(function(doc) { 
    doc.adds.filter(function(add){ return add.status = "PENDING" }).forEach(function(add) {
        bulk.find({ "_id": doc._id, "adds.status": "PENDING" }).updateOne({
            "$set": { "adds.$.status": "APPROVED" }
        });
        count++;

        // Execute once in 1000 statements created and re-init
        if ( count % 1000 == 0 ) {
            bulk.execute();
            bulk = db.collection.initializeOrderedBulkOp();
        }
    });
});

// Execute any pending operations
if ( count % 1000 != 0 )
    bulk.execute();

如果您要更新的文档很小,或者只有一个文档,那么您可以放弃计数检查,并在所需的循环中追加所有批量更新,然后在所有循环结束时执行一次。
更详细的说明和替代方案可以在如何更新多个数组元素中找到,但所有这些方法都归结为不同的匹配元素更新和处理位置$多次更新的方法,无论是每个匹配的文档还是直到没有返回修改的文档为止。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接