如何在MongoDB多层嵌套数组对象中更新指定likedID的like字段
正确更新MongoDB嵌套数组中指定字段的方法
问题背景
你的MongoDB文档结构如下:
[ { username: "user1", id: "1", Notifications: { history: { Messages: [Object], Collections: [ { Post: "text here", likes: [ { likedID: 8997, like: false }, { likedID: 988890, like: false } ] }, { Comment: "text here", likes: [ { likedID: 6898554, like: false }, { likedID: 333554321, like: false } ] } ] } } }, { username: "user2", id: "2", Notifications: { history: { Messages: [Object], Collections: [ { Post: "text here", likes: [ { likedID: 1245, like: false }, { likedID: 5675, like: false } ] } ] } } } ]
需求:找到并更新likedID为1245的对象的like字段值为true,你尝试的代码未成功:
db.user.update({ "Notifications..history.Collections": { "$all": [{ "$elemMatch": { likes: { "$all": [{ "$elemMatch": { likedID: 1245 } }] } } }] } }, { "$set": { "Notifications.history.Collections.$.likes": { like: true } } })
错误原因分析
- 路径语法错误:查询条件中的
Notifications..history.Collections多了一个点,正确路径应为Notifications.history.Collections - 查询条件冗余:嵌套使用
$all和$elemMatch完全没必要,只需简单匹配目标字段即可定位文档 - 更新路径错误:
Notifications.history.Collections.$.likes会直接替换整个likes数组,而非修改指定的单个元素
正确解决方案
使用MongoDB 3.2及以上版本支持的arrayFilters(数组过滤器),可以精准定位嵌套数组中的目标元素:
db.user.update( // 查询条件:匹配包含likedID=1245的文档 { "Notifications.history.Collections.likes.likedID": 1245 }, // 更新操作:修改指定元素的like字段 { $set: { "Notifications.history.Collections.$[col].likes.$[like].like": true } }, { // 数组过滤器:分别定位外层Collections和内层likes的目标元素 arrayFilters: [ { "col.likes.likedID": 1245 }, { "like.likedID": 1245 } ], // 可选:如果需要更新所有符合条件的文档,加上multi: true multi: true } )
代码说明
{ "Notifications.history.Collections.likes.likedID": 1245 }:快速定位包含目标元素的文档arrayFilters中的两个条件:{ "col.likes.likedID": 1245 }:匹配包含目标likes元素的Collections数组项{ "like.likedID": 1245 }:精准定位likes数组中likedID为1245的元素
multi: true:确保所有符合条件的文档都被更新(如果只需要更新第一个匹配文档,可省略该参数)
低版本兼容方案(MongoDB < 3.2)
如果你的MongoDB版本不支持arrayFilters,可以使用嵌套的位置操作符配合精确查询,但这种方法只能更新第一个匹配的嵌套元素:
db.user.update( { "Notifications.history.Collections": { "$elemMatch": { "likes.likedID": 1245 } } }, { $set: { "Notifications.history.Collections.$.likes.$[].like": function() { return this.likedID === 1245 ? true : this.like; } } } )
注:该方法依赖MongoDB的服务器端脚本,性能和灵活性不如
arrayFilters,建议优先升级版本使用数组过滤器。
内容的提问来源于stack exchange,提问作者Mahmoud Y3c
相关产品推荐
相关产品推荐

