Arrays 如何在mongodb中更新多个数组元素

Arrays 如何在mongodb中更新多个数组元素,arrays,mongodb,mongodb-query,Arrays,Mongodb,Mongodb Query,我有一个Mongo文档,它包含一个元素数组 我想重置数组中.profile=XX的所有对象的.handled属性 该文件的格式如下: { "_id": ObjectId("4d2d8deff4e6c1d71fc29a07"), "user_id": "714638ba-2e08-2168-2b99-00002f3d43c0", "events": [{ "handled": 1, "profile": 10,

我有一个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)
但是,它只更新每个文档中第一个匹配的数组元素。(这就是我们定义的行为。)

如何更新所有匹配的数组元素 从Mongo版本3.6开始,这个答案不再有效,因为所提到的问题已经解决,并且有办法实现这一点。请检查其他答案


此时,无法使用“位置”操作符更新数组中的所有项。见吉拉

作为一种工作环境,您可以:

  • 分别更新每个项目 (events.0.handled 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});
var集={},i,l;

对于(i=0,l=events.length;i而言,对我有效的是:

db.collection.find({ _id: ObjectId('4d2d8deff4e6c1d71fc29a07') })
  .forEach(function (doc) {
    doc.events.forEach(function (event) {
      if (event.profile === 10) {
        event.handled=0;
      }
    });
    db.collection.save(doc);
  });

我认为对于mongo新手和熟悉JQuery&friends的人来说,这一点更清楚。

这确实与长期存在的问题有关,在这个问题上,支持多数组匹配的“所有情况”的清晰语法实际上存在许多挑战。事实上,已经有一些方法可以“帮助”在解决这个问题的方法上,比如说在这篇原始帖子之后已经实施了

在单个update语句中更新多个匹配的数组元素仍然是不可能的,因此即使使用“多”update,对于该语句中的每个文档,您也只能更新数组中的一个匹配元素

目前最好的解决方案是查找并循环所有匹配的文档,并处理批量更新,这将至少允许在单个请求中以单个响应发送多个操作。您可以选择使用来减少搜索结果中返回的数组内容,使其仅与更新selec的条件匹配声明:

db.collection.aggregate([
{“$match”:{“events.handled”:1},
{“$project”:{
“事件”:{
“$setDifference”:[
{“$map”:{
“输入”:“$events”,
“作为”:“事件”,
“在”:{
“$cond”:[
{“$eq”:[“$$event.handled”,1]},
“$$el”,
假的
]
}
}},
[错误]
]
}
}}
]).forEach(功能(文档){
doc.events.forEach(函数(事件){
bulk.find({“\u id”:doc.\u id,“events.handled”:1}).updateOne({
“$set”:{”事件。$.handled::0}
});
计数++;
如果(计数%1000==0){
bulk.execute();
bulk=db.collection.initializeOrderedBulkOp();
}
});
});
如果(计数%1000!=0)
bulk.execute();
当数组有一个“唯一”标识符或每个元素的所有内容本身形成一个“唯一”元素时,
.aggregate()
部分将起作用。这是由于中的“set”运算符用于过滤从用于处理数组以进行匹配的操作返回的任何
false

如果您的阵列内容没有唯一元素,您可以尝试以下替代方法:

db.collection.aggregate([
{“$match”:{“events.handled”:1},
{“$redact”:{
“$cond”:{
“如果”:{
“$eq”:[{“$ifNull”:[“$handled”,1]},1]
},
“然后”:“$$down”,
“else”:“$$PRUNE”
}
}}
])
它的局限性在于,如果“handled”实际上是一个要在其他文档级别显示的字段,那么您很可能会得到未预期的结果,但如果该字段仅出现在一个文档位置,并且是相等匹配,则可以

在撰写本文时,未来版本(3.1版之后的MongoDB)将有一个更简单的
$filter
操作:

db.collection.aggregate([
{“$match”:{“events.handled”:1},
{“$project”:{
“事件”:{
“$filter”:{
“输入”:“$events”,
“作为”:“事件”,
“cond”:{“$eq”:[“$$event.handled”,1]}
}
}
}}
])
所有支持
.aggregate()
的发行版都可以使用以下方法,但由于管道中的阵列扩展,使用该操作符使其成为效率最低的方法:

db.collection.aggregate([
{“$match”:{“events.handled”:1},
{“$unwind”:“$events”},
{“$match”:{“events.handled”:1},
{“$组”:{
“\u id”:“$\u id”,
“事件”:{“$push”:“$events”}
}}        
])
在MongoDB版本支持聚合输出中的“游标”的所有情况下,这只是选择一种方法并使用处理批量更新语句所显示的相同代码块迭代结果的问题。聚合输出中的批量操作和“游标”在同一版本中引入(MongoDB 2.6)因此通常会手拉手进行加工

在甚至更早的版本中,最好只使用
.find()
返回游标,并过滤语句的执行,使其仅与
.update()匹配数组元素的次数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))
})
.update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function);
db.collection.update(
  { "events.profile":10 },
  { "$set": { "events.$[elem].handled": 0 } },
  { "arrayFilters": [{ "elem.profile": 10 }], "multi": true }
)
   db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
   db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
{
   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});
}
.update(   // or updateMany directly, removing the flag for 'multi'
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
   false,
   true
)
.update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)
db.collection.update(
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},
   {multi:true}
)
Notification.updateMany(
    { "_id": { $in: req.body.notificationIds } },
    {
        $pull: { "receiversId": req.body.userId }
    }, function (err) {
        if (err) {
            res.status(500).json({ "msg": err });
        } else {
            res.status(200).json({
                "msg": "Notification Deleted Successfully."
            });
        }
    });
db.collection.update({"events.profile":10}, { $set: { "events.$[elem].handled" : 0 } },
   {
     multi: true,
     arrayFilters: [ { "elem.profile": 10 } ]
})
db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: { 
 "arr.$[].status" : "completed"
} }
)
db.collectioname.updateOne(
 { key:"someunique", "arr.key": "myuniq" },
 { $set: { 
   "arr.$.status" : "completed", 
   "arr.$.msgs":  {
                "result" : ""
        }
   
 } }
)
db.collectioname.find({findCriteria })
  .forEach(function (doc) {
    doc.arr.forEach(function (singlearr) {
      if (singlearr check) {
        singlearr.handled =0
      }
    });
    db.collection.save(doc);
  });