Mongoose更新嵌套数组多匹配元素仅命中首个匹配的问题
原有更新语句的核心问题
本质是$单位置操作符的固有设计限制导致,和multi:true参数的作用无关:
$位置操作符仅能指向查询条件命中的第一个数组元素的下标,无论数组内有多少个元素符合查询规则,同一次更新操作只会修改这个第一个命中的元素multi:true的作用是让更新操作覆盖所有符合查询条件的顶层文档,完全不会扩大单个数组内的元素更新范围,无法突破单$操作符的单元素命中限制- 你的测试场景中,items数组遍历第一个命中查询条件的元素是id=15的项,因此
items.$.score只会修改该元素的score值,同数组内id=14的匹配元素不会被更新
场景适配的正确更新写法
MongoDB 3.6及以上版本(官方推荐实现)
使用带命名过滤的位置操作符$[<identifier>]配合arrayFilters参数,实现数组内多匹配元素的批量更新:
db.collection.update( // 匹配需要执行更新的顶层文档 { "items.id": { $in: [14, 15] } }, { $set: { "items.$[elem].score": 444 } }, { multi: true, // 定义数组元素的过滤规则,所有符合规则的数组元素都会被更新 arrayFilters: [ { "elem.id": { $in: [14, 15] } } ] } )
该语句执行后,items数组中所有id为14、15的元素的score字段都会被统一更新为444,id为12的非匹配元素不会被改动。
MongoDB 3.6以下旧版本兼容方案
旧版本不支持arrayFilters能力,可通过文档遍历的方式实现批量更新:
- 读取所有顶层查询条件命中的文档
- 遍历每个文档的items数组,将id匹配14、15的元素的score值替换为目标值
- 将修改后的文档回写至集合完成更新
内容的提问来源于stack exchange,提问作者notnotundefined
相关产品推荐
相关产品推荐

