如何用Mongoose按ID批量更新文档中数组内的多个对象?
批量更新MongoDB文档中数组内的多个元素
要实现单查询批量更新目标文档的exp字段,以及items、stats数组中指定ID元素的对应字段,你可以使用MongoDB 3.6+支持的arrayFilters特性,结合$set操作符完成。
直接写法(固定更新项)
await DataModel.findOneAndUpdate( { "id": idvariable }, // 匹配目标文档的id { "$set": { "exp": "555", // 按顺序更新items数组中对应ID元素的qty "items.$[itemElem].qty": [44, 55, 66, 77], // 按顺序更新stats数组中对应ID元素的strenght "stats.$[statElem].strenght": [10, 20, 12, 54] } }, { arrayFilters: [ // 匹配items数组中需要更新的ID集合 { "itemElem.ID": { $in: [ ObjectId("kieryu35261twerts73940djr"), ObjectId("1240a1ffuw33dbcv6ut8888zz"), ObjectId("5600r0e0rr67cbd60a1234y5"), ObjectId("32bbd0e0rr92cdb60a4386c7") ] } }, // 匹配stats数组中需要更新的ID集合 { "statElem.ID": { $in: [ ObjectId("3eruskdjfhrutiwo4059yuol3"), ObjectId("3jdks0d9r2seifldvjmw0km2e"), ObjectId("aslkdnasklnc2112uhnsjssad"), ObjectId("1230msafmlklkmasfmcio3kms") ] } } ], new: true // 可选,返回更新后的文档 } );
写法说明
arrayFilters用于定义数组元素的匹配规则,$[itemElem]和$[statElem]是占位符,分别对应items和stats数组中符合过滤条件的元素。$set中的更新值数组顺序必须和arrayFilters里$in的ID顺序完全一致,才能保证每个ID对应正确的更新值。
动态构建更新项(推荐,避免顺序错误)
如果更新项较多或需要动态生成,建议通过对象映射的方式构建更新参数,避免手动对应顺序出错:
// 定义需要更新的items数据:ID对应目标qty const itemsUpdates = [ { id: ObjectId("kieryu35261twerts73940djr"), qty: 44 }, { id: ObjectId("1240a1ffuw33dbcv6ut8888zz"), qty: 55 }, { id: ObjectId("5600r0e0rr67cbd60a1234y5"), qty: 66 }, { id: ObjectId("32bbd0e0rr92cdb60a4386c7"), qty: 77 } ]; // 定义需要更新的stats数据:ID对应目标strenght const statsUpdates = [ { id: ObjectId("3eruskdjfhrutiwo4059yuol3"), strenght: 10 }, { id: ObjectId("3jdks0d9r2seifldvjmw0km2e"), strenght: 20 }, { id: ObjectId("aslkdnasklnc2112uhnsjssad"), strenght: 12 }, { id: ObjectId("1230msafmlklkmasfmcio3kms"), strenght: 54 } ]; // 构建$set操作的内容 const setObj = { "exp": "555" }; // 构建arrayFilters数组 const arrayFilters = []; // 处理items的更新规则 itemsUpdates.forEach((update, index) => { const filterKey = `itemFilter${index}`; // 给setObj添加对应字段的更新值 setObj[`items.$[${filterKey}].qty`] = update.qty; // 添加对应的过滤条件 arrayFilters.push({ [`${filterKey}.ID`]: update.id }); }); // 处理stats的更新规则 statsUpdates.forEach((update, index) => { const filterKey = `statFilter${index}`; setObj[`stats.$[${filterKey}].strenght`] = update.strenght; arrayFilters.push({ [`${filterKey}.ID`]: update.id }); }); // 执行更新操作 await DataModel.findOneAndUpdate( { "id": idvariable }, { "$set": setObj }, { arrayFilters, new: true } );
注意事项
- 确保你的MongoDB版本在3.6及以上,
arrayFilters是该版本才引入的特性。 - 使用
ObjectId时,需要确保已经正确引入MongoDB的ObjectId类(比如const { ObjectId } = require('mongoose');或import { ObjectId } from 'mongodb';)。 - 如果不需要返回更新后的文档,可以去掉
new: true参数。
内容的提问来源于stack exchange,提问作者Rizkiramadhani
相关产品推荐
相关产品推荐

