如何在MongoDB中使用聚合操作更新数组值与完成百分比字段
问题解决方案
错误原因
你的写法存在两个核心语法错误:
arrayFilters、multi属于findOneAndUpdate的选项参数,是方法的第三个入参,你错误将其放到了更新操作的聚合管道数组中,导致语法解析失败。$[element]这类带标识符的数组过滤更新操作符,仅支持普通更新对象场景,不能在聚合更新管道中使用,因此无法和后续计算percentageCompleted的聚合逻辑放在同一个管道数组中。
正确实现方案
我们可以直接在聚合管道中使用$map遍历数组修改指定元素,再同步计算完成率,一次操作完成两个需求,完整代码如下:
db.orders.findOneAndUpdate( // 查询条件:匹配指定订单 { _id: ObjectId('60b114b2415731001943b17f') }, // 聚合更新管道 [ // 第一步:修改指定工序的isCompleted状态 { $set: { processList: { $map: { input: "$processList", as: "process", in: { $cond: [ // 匹配对应id的工序 { $eq: ["$$process.id", "60b0f0e9659a3b001c235300"] }, // 匹配成功则修改isCompleted为true,其余字段保留 { $mergeObjects: ["$$process", { isCompleted: true }] }, // 匹配失败则保留原数据 "$$process" ] } } } } }, // 第二步:同步计算更新完成百分比(原有逻辑可直接复用) { $set: { percentageCompleted: { $multiply: [ { $divide: [ { $size: { $filter: { input: "$processList", as: "p", cond: { $eq: ["$$p.isCompleted", true] } } } }, { $size: "$processList" } ] }, 100 ] } } } ], // 可选配置:返回更新后的文档 { returnNewDocument: true } )
可选方案(使用arrayFilters写法)
如果你更习惯用arrayFilters的写法,可以拆分为两次更新操作,不过性能略低于上面的单次聚合更新方案:
// 第一步:更新指定工序状态 db.orders.updateOne( { _id: ObjectId('60b114b2415731001943b17f') }, { $set: {"processList.$[element].isCompleted": true} }, { arrayFilters: [{ 'element.id': "60b0f0e9659a3b001c235300" }] } ) // 第二步:计算更新完成率 db.orders.findOneAndUpdate( { _id: ObjectId('60b114b2415731001943b17f') }, [ { $set: { percentageCompleted: { $multiply: [ { $divide: [{ $size: { $filter: { input: "$processList", as: "p", cond: { $eq: ["$$p.isCompleted", true] } } } }, { $size: "$processList" }] }, 100 ] } } } ], { returnNewDocument: true } )
内容的提问来源于stack exchange,提问作者user2453753
相关产品推荐
相关产品推荐

