如何对嵌套数组内指定分组的items子数组求和并更新total字段
实现方案
以下两种方案均可实现需求,可根据你使用的MongoDB版本选择:
方案1:MongoDB 4.2+ 聚合更新(推荐)
该版本支持直接在update操作中传入聚合管道,无需额外查询,一步完成更新,不需要使用$unwind操作:
// 示例为更新group_id为A的分组total字段 db.collection.updateOne( // 匹配包含目标分组的文档,可补充其他文档筛选规则 { "groups.group_id": "A" }, [ { $set: { groups: { $map: { input: "$groups", as: "group", in: { $cond: { if: { $eq: ["$$group.group_id", "A"] }, // 仅修改目标分组,其余分组保持不变 then: { $mergeObjects: [ "$$group", { total: { $sum: "$$group.items.val" } } ] }, else: "$$group" } } } } } } ] )
逻辑说明:
- 外层
$match先过滤出存在目标分组的文档,减少无效扫描 $map遍历groups数组,仅对指定group_id的元素做修改$sum直接对目标分组下的items.val数组求和,无需拆分数组$mergeObjects保留分组原有全部字段,仅覆盖total值,不会丢失数据
方案2:含$unwind的兼容方案(支持MongoDB 4.2以下版本)
如果你需要使用$unwind操作,或是MongoDB版本较低不支持聚合更新,可先查询计算总和再执行更新:
// 第一步:查询计算目标分组的val总和 const aggResult = db.collection.aggregate([ { $match: { "groups.group_id": "A" } }, // 拆分groups数组 { $unwind: "$groups" }, // 仅保留目标分组的记录,不处理其他分组 { $match: { "groups.group_id": "A" } }, { $project: { total: { $sum: "$groups.items.val" }, _id: 1 } } ]).toArray() // 第二步:执行更新 if (aggResult.length > 0) { const { _id, total } = aggResult[0] db.collection.updateOne( { _id: _id, "groups.group_id": "A" }, { $set: { "groups.$.total": total } } ) }
提示:将上述代码中的
A替换为你实际要操作的group_id,db.collection替换为你的真实集合名称即可运行。如果需要同时更新多个符合条件的文档,将updateOne替换为updateMany即可。
内容的提问来源于stack exchange,提问作者IsaacLevon
相关产品推荐
相关产品推荐

