我有一个Mongo文档,其中包含一个元素数组。

我想重置.profile = XX数组中所有对象的.handled属性。

文件格式如下:

{
    "_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
    "user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
    "events": [{
            "handled": 1,
            "profile": 10,
            "data": "....."
        } {
            "handled": 1,
            "profile": 10,
            "data": "....."
        } {
            "handled": 1,
            "profile": 20,
            "data": "....."
        }
        ...
    ]
}

所以,我尝试了以下方法:

.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)

但是,它只更新每个文档中第一个匹配的数组元素。(这是$ -位置操作符的定义行为。)

如何更新所有匹配的数组元素?


当前回答

我一直在使用c# 3.6的最新驱动程序寻找解决方案,下面是我最终确定的解决方案。这里的关键是使用“$[]”,根据MongoDB 3.6版的新版本。参见https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up.S[]了解更多信息。

代码如下:

{
   var filter = Builders<Scene>.Filter.Where(i => i.ID != null);
   var update = Builders<Scene>.Update.Unset("area.$[].discoveredBy");
   var result = collection.UpdateMany(filter, update, new UpdateOptions { IsUpsert = true});
}

要了解更多信息,请参阅我的原文: 使用MongoDB c#驱动程序从所有文档中删除数组元素

其他回答

请注意,在这个帖子中建议使用$[]的一些答案是错误的。

db.collection.update(
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},
   {multi:true}
)

上面的代码将“events”数组中的所有元素的“handled”更新为0,不管它的“profile”值是多少。查询{"events. events. "Profile ":10}仅用于过滤整个文档,而不是数组中的文档。在这种情况下,必须使用$[elem]和arrayFilters来指定数组项的条件,以便Neil Lunn的答案是正确的。

$[]操作符选择所有嵌套数组。使用'$[]'可以更新所有数组项

.update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)

参考

首先:您的代码无法工作,因为您使用了位置操作符$,该操作符仅标识数组中要更新的元素,但甚至没有显式地指定其在数组中的位置。

您需要的是筛选位置操作符$[<identifier>]。它将更新所有匹配数组筛选条件的元素。

解决方案:

db.collection.update({"events.profile":10}, { $set: { "events.$[elem].handled" : 0 } },
   {
     multi: true,
     arrayFilters: [ { "elem.profile": 10 } ]
})

点击这里访问mongodb doc

代码的作用:

{"events.profile":10} filters your collection and return the documents matching the filter The $set update operator: modifies matching fields of documents it acts on. {multi:true} It makes .update() modifies all documents matching the filter hence behaving like updateMany() { "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ] This technique involves the use of the filtered positional array with arrayFilters. the filtered positional array here $[elem] acts as a placeholder for all elements in the array fields that match the conditions specified in the array filter.

数组的过滤器

更新: 从Mongo 3.6版开始,这个答案不再有效,因为上面提到的问题已经修复,有办法实现这一点。请检查其他答案。


此时,不可能使用位置操作符来更新数组中的所有项。参见JIRA http://jira.mongodb.org/browse/SERVER-1243

作为一份工作,你可以:

单独更新每个项目 (events.0。处理events.1.handled )或… 阅读文件,进行编辑 手动保存并替换 旧版本(勾选“如果更新 如果你想确保“当前” 原子更新)

您可以更新MongoDB中的所有元素

db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: { 
 "arr.$[].status" : "completed"
} }
)

它将更新“arr”数组中所有的“status”值为“completed”

如果只有一份文件

db.collectioname.updateOne(
 { key:"someunique", "arr.key": "myuniq" },
 { $set: { 
   "arr.$.status" : "completed", 
   "arr.$.msgs":  {
                "result" : ""
        }
   
 } }
)

但如果不是一个,而且你也不希望数组中的所有文档都更新,那么你需要遍历元素和if块内部

db.collectioname.find({findCriteria })
  .forEach(function (doc) {
    doc.arr.forEach(function (singlearr) {
      if (singlearr check) {
        singlearr.handled =0
      }
    });
    db.collection.save(doc);
  });