如何在mongodb中更新多个数组元素
如何在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)
然而,它只更新每个文档中第一个匹配的数组元素。(这是$ - 定位操作符的定义行为。)
我如何更新所有匹配的数组元素?
更新:
从Mongo版本3.6开始,本答案不再有效,因为所提到的问题已经修复,有方法可以实现。请查看其他答案。
目前无法使用位置操作符来更新数组中的所有项。请参见JIRA http://jira.mongodb.org/browse/SERVER-1243
作为解决方法,您可以:
- 逐个更新每个项目
(events.0.handled events.1.handled
...)或... - 读取文档,手动编辑并保存以替换旧的文档(如果要确保原子更新,请查看"Current更新")
随着 MongoDB 3.6 的发布(并且从 MongoDB 3.5.12 开始可用于开发分支),您现在可以在单个请求中更新多个数组元素。
这使用了在这个版本中引入的 有过滤的位置标识符 $[
更新操作符语法:
db.collection.update( { "events.profile":10 }, { "$set": { "events.$[elem].handled": 0 } }, { "arrayFilters": [{ "elem.profile": 10 }], "multi": true } )
传递给 .update()
或甚至 .updateOne()
、.updateMany()
、.findOneAndUpdate()
或 .bulkWrite()
方法的选项中的 "arrayFilters"
指定在更新语句中给定的标识符上匹配的条件。任何匹配条件的元素都将被更新。
需注意,问题中给出的 "multi"
在预期中使用是为了"更新多个元素",但这不是也仍然不是该情况。它在这里的使用适用于 "多个文档",一直是这样,或现在在现代 API 版本中以强制设置为 .updateMany()
。
注意 有些讽刺的是,虽然
.update()
和类似方法中的"选项"参数指定了这个语法,但这个语法通常与最近版本的驱动程序兼容。然而,
mongo
shell就不是这样了,因为它的实现方式("具有讽刺意味的是,为了向后兼容")不识别并移除arrayFilters
参数,通过解析选项以向先前的MongoDB服务器版本提供"向后兼容性"和"遗留"的.update()
API调用语法。因此,如果您想在
mongo
shell或其他"基于shell"的产品(特别是Robo 3T)中使用该命令,您需要获得开发分支或版本发布的最新版本,版本需要是3.6或更高版本。
参见位置加全部$[]
,它也可以更新"多个数组元素",但不适用于指定的条件,并适用于数组中的所有元素,如果需要这个操作。
还可以参见使用MongoDB更新嵌套数组,了解这些新的位置操作符如何应用于"嵌套"数组结构,其中"数组在其他数组中"。
重要 - 从以前版本升级的安装可能没有启用MongoDB功能,这也可能导致语句失败。您应该确保您的升级过程已经完成详细的任务,例如索引升级,然后运行
db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
或是适用于您安装版本的更高版本。例如,当前版本4及以后版本的
"4.0"
。这使得新的位置更新操作符和其他功能成为可能。您也可以使用以下方式进行检查:db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
返回当前设置