MongoDB更新多层嵌套数组中指定objectId对应元素字段
MongoDB嵌套数组按objectId更新字段方案
问题描述
现有如下MongoDB文档结构:
{ _id: ObjectId('61ae12bfb8047effd0ac2a01'), data: [ { xml: { messageId: 1638798015073, xmlString: 'someXML' }, data: [ { customerId: 123456, validation: { isValid: true, message: '' }, docs: [ { objectId: 'PA1106:zt:bb302216879669b58c141b12dcdd5eb0', writtenBack: false } ] }, { customerId: 55555, validation: { isValid: true, message: '' }, docs: [ { objectId: 'PA1106:zt:bb302216879669b58b143ef38c016217', writtenBack: true } ] } ] }, { xml: { messageId: 1638798015094, xmlString: 'someXML' }, data: [ { customerId: 55555, validation: { isValid: true, message: '' }, docs: [ { objectId: 'PA1106:zt:bb302216879669b58c1416129062c2d2', writtenBack: false }, { objectId: 'PA1106:zt:b8be9ea04011c2a18c148a0d4c9d6aab', writtenBack: true } ] } ] } ], createdAt: '2021-12-06T13:40:15.096Z', createdBy: 'Test' }
需求为指定根文档下,根据全局唯一的objectId更新对应docs数组元素的writtenBack属性。
初始尝试的更新语句如下,无法正确命中目标元素:
// 查询条件 { _id: '61ae12bfb8047effd0ac2a01', 'data.data.docs.objectId': 'PA1106:zt:bb302216879669b58b143ef38c016217' }, // 更新操作 { $set: { 'data.data.docs.$.writtenBack': true } }
已知arrayFilters可处理嵌套数组更新,但常规认知中需要为每一层数组提供唯一过滤标识,当前仅持有objectId字段,需要可行实现方案。
正确实现方式
不需要为每一层数组提前准备唯一标识,arrayFilters支持仅对需要匹配的层级设置过滤规则,外层数组会自动遍历匹配,具体语句如下:
db.collection.updateOne( // 根文档匹配条件,仅需匹配_id即可 { _id: ObjectId('61ae12bfb8047effd0ac2a01') }, // 更新操作,为三层嵌套数组分别定义占位符 { $set: { 'data.$[level1].data.$[level2].docs.$[level3].writtenBack': true } }, { arrayFilters: [ // 仅需为最内层docs数组设置匹配规则,外层无需额外过滤 { 'level3.objectId': 'PA1106:zt:bb302216879669b58b143ef38c016217' } ] } )
注意事项
- 占位符
level1/level2/level3可自定义命名,只要和arrayFilters中的标识对应即可 - 外层占位符不需要配置过滤规则,MongoDB会自动遍历所有层级的数组元素,找到符合
objectId匹配规则的元素执行更新 - 由于
objectId是全局唯一字段,该写法不会出现误更新其他元素的问题 - 根文档的
_id是ObjectId类型,查询时不要直接传入字符串,需要用ObjectId()方法包装,否则无法命中目标根文档 - 该写法适用于MongoDB 3.6及以上版本(
arrayFilters特性从3.6版本开始正式支持)
内容的提问来源于stack exchange,提问作者azmd108
相关产品推荐
相关产品推荐

