为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

DIEA 2019-05-24 14:42:31

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

我有一个Mongo文档,其中包含一系列元素。

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

该文件采用以下形式:

{
    "_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)

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

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


查看完整描述

4 回答

?
繁星淼淼

此时,无法使用位置运算符更新数组中的所有项目。见JIRA http://jira.mongodb.org/browse/SERVER-1243

作为一种解决方法,您可以:

  • 单独更新每个项目(events.0.handled events.1.handled ...)或......

  • 阅读文档,手动编辑并保存以替换旧版本(如果要确保原子更新,请选中“如果当前更新”)


查看完整回答
反对 回复 2019-05-24
?
蝴蝶刀刀

对我有用的是:

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和朋友的人都会更清楚。


查看完整回答
反对 回复 2019-05-24
?
红颜莎娜

随着MongoDB 3.6发布(以及MongoDB 3.5.12的开发分支中提供),您现在可以在单个请求中更新多个数组元素。

这使用此版本中引入的过滤位置$[<identifier>]更新运算符语法:

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

"arrayFilters"它被传递到选项.update(),甚至.updateOne().updateMany().findOneAndUpdate().bulkWrite()方法指定要匹配的UPDATE语句给出的标识符的条件。任何符合条件的元素都将被更新。

注意到"multi"在问题的上下文中给出的内容被用于期望这将“更新多个元素”,但这不是,现在仍然不是这样。这里的用法适用于“多个文档”,因为一直是这种情况,或者现在以其他方式指定为.updateMany()现代API版本的强制设置。

注意有点讽刺的是,因为这是在方法的“options”参数中指定的.update(),所以语法通常与所有最新的发行版驱动程序版本兼容。

但是对于mongoshell 来说并非如此,因为在那里实现该方法的方式(“具有讽刺意味的是为了向后兼容性”),该arrayFilters参数不被内部方法识别和删除,该方法解析选项以便与先前提供“向后兼容性”。 MongoDB服务器版本和“遗留” .update()API调用语法。

因此,如果您想在mongoshell或其他“基于shell”的产品(特别是Robo 3T)中使用该命令,则需要3.6或更高版本的开发分支或生产版本的最新版本。

另请参见positional all $[]哪些更新“多个数组元素”但不应用于指定的条件,并应用于数组中所需的操作所有元素。

另请参阅使用MongoDB更新嵌套数组,了解这些新的位置运算符如何应用于“嵌套”数组结构,其中“数组位于其他数组中”。

重要信息 - 以前版本的升级安装“可能”尚未启用MongoDB功能,这也可能导致语句失败。您应确保升级过程完成,并提供索引升级等详细信息,然后运行

   db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

或更高版本适用于您安装的版本。即"4.0"目前版本4及以后版本。这启用了诸如新位置更新操作符等功能。您还可以查看:

   db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

要返回当前设置


查看完整回答
反对 回复 2019-05-24
?
ABOUTYOU

这也可以通过while循环来完成,该循环检查是否仍有任何文档仍然具有尚未更新的子文档。此方法保留了更新的原子性(这里的许多其他解决方案都没有)。

var query = {
    events: {
        $elemMatch: {
            profile: 10,
            handled: { $ne: 0 }
        }
    }};while (db.yourCollection.find(query).count() > 0) {
    db.yourCollection.update(
        query,
        { $set: { "events.$.handled": 0 } },
        { multi: true }
    );}

执行循环的次数将等于集合中任何文档中出现的profile等于10 handled且不等于0的子文档的最大次数。因此,如果您的集合中有100个文档,并且其中一个文档具有三个匹配的子文档,query并且所有其他文档具有较少的匹配子文档,则循环将执行三次。

此方法避免了在此脚本执行时破坏可能由另一个进程更新的其他数据的危险。它还最大限度地减少了客户端和服务器之间传输的数据量。


查看完整回答
反对 回复 2019-05-24

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信