我有一个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)

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

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


当前回答

实际上,save命令只在Document类的实例上。 有很多方法和属性。因此可以使用lean()函数来减少工作负载。 请参考这里。https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

保存功能的另一个问题是,同时在多个保存中会产生冲突数据。 模型。更新将使数据一致。 因此要更新文档数组中的多个项目。使用你熟悉的编程语言,尝试这样的东西,我用mongoose:

User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec()
  .then(usr =>{
    if(!usr)  return
    usr.events.forEach( e => {
      if(e && e.profile==10 ) e.handled = 0
    })
    User.findOneAndUpdate(
      {'_id': '4d2d8deff4e6c1d71fc29a07'},
      {$set: {events: usr.events}},
      {new: true}
    ).lean().exec().then(updatedUsr => console.log(updatedUsr))
})

其他回答

实际上,save命令只在Document类的实例上。 有很多方法和属性。因此可以使用lean()函数来减少工作负载。 请参考这里。https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j

保存功能的另一个问题是,同时在多个保存中会产生冲突数据。 模型。更新将使数据一致。 因此要更新文档数组中的多个项目。使用你熟悉的编程语言,尝试这样的东西,我用mongoose:

User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec()
  .then(usr =>{
    if(!usr)  return
    usr.events.forEach( e => {
      if(e && e.profile==10 ) e.handled = 0
    })
    User.findOneAndUpdate(
      {'_id': '4d2d8deff4e6c1d71fc29a07'},
      {$set: {events: usr.events}},
      {new: true}
    ).lean().exec().then(updatedUsr => console.log(updatedUsr))
})

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


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

作为一份工作,你可以:

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

我很惊讶这个问题在mongo中还没有解决。总的来说,mongo在处理子数组时似乎不太好。例如,不能简单地计算子数组。

我用了哈维尔的第一个方法。将数组读入事件,然后循环并构建set exp:

var set = {}, i, l;
for(i=0,l=events.length;i<l;i++) {
  if(events[i].profile == 10) {
    set['events.' + i + '.handled'] = 0;
  }
}

.update(objId, {$set:set});

可以使用条件测试的回调将其抽象为一个函数

您可以更新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);
  });

这个帖子很老了,但我来这里寻找答案,因此提供了新的解决方案。

在MongoDB 3.6+版本中,现在可以使用位置操作符更新数组中的所有项。点击这里查看官方文件。

下面的问题将适用于这里提出的问题。我也用Java-MongoDB驱动进行了验证,工作成功。

.update(   // or updateMany directly, removing the flag for 'multi'
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
   false,
   true
)

希望这能帮助到像我这样的人。