如何在MongoDB中对含嵌套对象数组的多文档执行分组聚合
MongoDB聚合实现方案
核心思路
- 第一阶段:全局分组聚合,先累加所有文档
scalar字段的总和,同时收集所有文档的array、array2元素合并为单个数组 - 第二阶段:对合并后的
array、array2分别用$reduce算子按key分组,对同key的value求和
完整聚合查询代码
db.collection.aggregate([ // 阶段1:全局分组,聚合基础数据 { $group: { _id: null, scalar: { $sum: "$scalar" }, allArray: { $push: "$array" }, allArray2: { $push: "$array2" } } }, // 阶段2:把分组得到的二维数组合并为一维数组,方便后续处理 { $project: { _id: 0, scalar: 1, allArray: { $concatArrays: "$allArray" }, allArray2: { $concatArrays: "$allArray2" } } }, // 阶段3:用$reduce对两个数组分别按key求和 { $project: { scalar: 1, array: { $reduce: { input: "$allArray", initialValue: [], in: { $let: { vars: { // 查找当前累加数组中是否存在和当前元素key相同的项 existingIndex: { $indexOfArray: ["$$value.key", "$$this.key"] } }, in: { $cond: { // 存在同key项则累加value if: { $ne: ["$$existingIndex", -1] }, then: { $concatArrays: [ { $slice: ["$$value", "$$existingIndex"] }, [ { key: "$$this.key", value: { $sum: [{ $arrayElemAt: ["$$value.value", "$$existingIndex"] }, "$$this.value"] } } ], { $slice: ["$$value", { $add: ["$$existingIndex", 1] }, { $size: "$$value" }] } ] }, // 不存在同key项则直接追加 else: { $concatArrays: ["$$value", ["$$this"]] } } } } } } }, // array2处理逻辑和array完全一致,仅替换输入数组即可 array2: { $reduce: { input: "$allArray2", initialValue: [], in: { $let: { vars: { existingIndex: { $indexOfArray: ["$$value.key", "$$this.key"] } }, in: { $cond: { if: { $ne: ["$$existingIndex", -1] }, then: { $concatArrays: [ { $slice: ["$$value", "$$existingIndex"] }, [ { key: "$$this.key", value: { $sum: [{ $arrayElemAt: ["$$value.value", "$$existingIndex"] }, "$$this.value"] } } ], { $slice: ["$$value", { $add: ["$$existingIndex", 1] }, { $size: "$$value" }] } ] }, else: { $concatArrays: ["$$value", ["$$this"]] } } } } } } } } } ])
本方案兼容MongoDB 3.4及以上版本,全部使用原生聚合算子实现,不需要额外开启服务端JS执行权限。
内容的提问来源于stack exchange,提问作者hieumdd
相关产品推荐
相关产品推荐

