如何在Mongoose中更新多个数组对象字段?
问题:批量更新MongoDB数组中匹配元素的字段值
我的Mongoose文档结构如下:
[ { "user": "63bue258j43747143hi059d7", "images": [ { "image_link": "first-unique-link-http::link-to-image1-63", "inStock": false }, { "image_link": "second-unique-link-http::link-to-image2-63", "inStock": false }, { "image_link": "third-unique-link-http::link-to-image3-63", "inStock": false } ] }, { "user": "9Ef53258j4374714phk625b3", "images": [ { "image_link": "anotherFirst-unique-link-http::link-to-image1-9E", "inStock": false }, { "image_link": "anotherSecond-unique-link-http::link-to-image2-9E", "inStock": false } ] } ]
需求:查询数据库,将所有匹配指定image_link数组的元素的inStock字段更新为true。
我尝试的查询语句:
const imgArr = ['first-unique-link-http::link-to-image1-63', 'third-unique-link-http::link-to-image3-63', 'anotherSecond-unique-link-http::link-to-image2-9E'] const updateStockStatus = await ImageStock.update( { "images.image_link": { $in: imgArr } }, { $set: { 'images.inStock' : true } }, {multi: true} )
期望更新后的文档结构:
[ { "user": "63bue258j43747143hi059d7", "images": [ { "image_link": "first-unique-link-http::link-to-image1-63", "inStock": true }, { "image_link": "second-unique-link-http::link-to-image2-63", "inStock": false }, { "image_link": "third-unique-link-http::link-to-image3-63", "inStock": true } ] }, { "user": "9Ef53258j4374714phk625b3", "images": [ { "image_link": "anotherFirst-unique-link-http::link-to-image1-9E", "inStock": false }, { "image_link": "anotherSecond-unique-link-http::link-to-image2-9E", "inStock": true } ] } ]
问题分析
你当前的写法会把匹配文档中所有images元素的inStock设为true,而非仅更新image_link在目标数组里的元素。原因是直接使用'images.inStock'会定位到整个数组的所有子文档字段,没有指定精准的匹配条件。
解决方案
方法一:使用arrayFilters(推荐,支持多元素匹配)
这是适配你场景的最优方案,通过arrayFilters指定过滤规则,批量更新所有符合条件的数组元素:
const imgArr = ['first-unique-link-http::link-to-image1-63', 'third-unique-link-http::link-to-image3-63', 'anotherSecond-unique-link-http::link-to-image2-9E'] const updateStockStatus = await ImageStock.updateMany( {}, { $set: { 'images.$[elem].inStock': true } }, { multi: true, arrayFilters: [{ 'elem.image_link': { $in: imgArr } }] } )
updateMany会遍历所有文档(若需限制范围,可保留原查询条件{ "images.image_link": { $in: imgArr } })$[elem]是数组过滤器的占位符,对应arrayFilters中定义的规则arrayFilters精准指定只更新image_link存在于imgArr中的数组元素
执行后即可得到你期望的结果,仅匹配的元素inStock被设为true,其他元素保持原样。
方法二:使用$操作符(仅适用于单元素匹配)
如果每个文档中只有一个image_link匹配目标数组,可使用此方法:
const imgArr = ['first-unique-link-http::link-to-image1-63', 'third-unique-link-http::link-to-image3-63', 'anotherSecond-unique-link-http::link-to-image2-9E'] const updateStockStatus = await ImageStock.updateMany( { "images.image_link": { $in: imgArr } }, { $set: { 'images.$.inStock': true } }, { multi: true } )
注意:$操作符仅会更新数组中第一个匹配条件的元素,若一个文档中有多个匹配项(如第一个文档里的两个链接),此方法无法满足需求。
内容的提问来源于stack exchange,提问作者Otis
相关产品推荐
相关产品推荐

