MongoDB更新管道中如何按索引修改深层嵌套数组内元素的字段
问题根因
你原先的写法出错是因为MongoDB更新管道中不支持通过xxx.0.xxx的点语法直接定位数组索引位置,这里的0会被识别为对象的字段名而非数组下标,因此才会在元素内新增0字段。
正确实现方案
你需要配合数组操作符处理指定位置的元素更新,有两种常用的实现方式:
方案1(适用无重复元素的场景)
通过$map遍历数组+$indexOfArray匹配索引,写法更直观:
const materialId = "m1"; const targetIndex = 0; const newAmount = 100; await products.findOneAndUpdate(filters, [ { $set: { // 动态拼接材料id的路径 [`materials.${materialId}.inventory`]: { $map: { input: `$materials.${materialId}.inventory`, as: "item", in: { $cond: { // 匹配当前元素的索引是否为目标索引 if: { $eq: [{ $indexOfArray: [`$materials.${materialId}.inventory`, "$$item"] }, targetIndex] }, // 匹配成功则合并更新amount字段 then: { $mergeObjects: ["$$item", { amount: newAmount }] }, // 匹配失败返回原元素 else: "$$item" } } } }, // 此处可继续添加其他需要更新的字段 } }, // 若有unset需求,可在此添加对应的$unset阶段 // { $unset: ["需要删除的字段路径1", "需要删除的字段路径2"] } ]);
方案2(通用高性能方案)
通过数组切片拼接的方式更新,不会受重复元素影响,性能更高:
$set: { [`materials.${materialId}.inventory`]: { $let: { vars: { arr: `$materials.${materialId}.inventory` }, in: { $concatArrays: [ // 取目标索引之前的所有元素 { $slice: ["$$arr", targetIndex] }, // 合并更新目标索引的元素 [ { $mergeObjects: [ { $arrayElemAt: ["$$arr", targetIndex] }, { amount: newAmount } ] } ], // 取目标索引之后的所有元素 { $slice: ["$$arr", targetIndex + 1, { $size: "$$arr" }] } ] } } } }
内容的提问来源于stack exchange,提问作者Aruna Herath
相关产品推荐
相关产品推荐

