MongoDB三层嵌套文档如何按parentId和日期分组聚合各字段总和
实现方案
你需要用MongoDB的聚合管道结合$objectToArray、$arrayToObject处理动态字段,具体管道步骤如下:
db.collection.aggregate([ // 步骤1:拆分时间为年、月、日,同时把stats.type下的所有子对象合并打平 { $addFields: { year: { $year: "$time" }, month: { $month: "$time" }, day: { $dayOfMonth: "$time" }, // 把stats.type的所有值(a、b、c对应的对象)转成数组后拼接,拿到所有n:xx的键值对 allStats: { $reduce: { input: { $objectToArray: "$stats.type" }, initialValue: [], in: { $concatArrays: ["$$value", { $objectToArray: "$$this.v" }] } } } } }, // 步骤2:把打平的键值对拆成独立文档,方便后续分组求和 { $unwind: "$allStats" }, // 步骤3:按parentId、年月日、n字段名分组,求和 { $group: { _id: { parentId: "$parentId", year: "$year", month: "$month", day: "$day", nKey: "$allStats.k" }, total: { $sum: "$allStats.v" } } }, // 步骤4:重新按parentId、年月日分组,把所有n字段和值拼成一个对象 { $group: { _id: { parentId: "$_id.parentId", year: "$_id.year", month: "$_id.month", day: "$_id.day" }, nFields: { $push: { k: "$_id.nKey", v: "$total" } } } }, // 步骤5:把nFields转成顶层字段,补全输出格式 { $replaceRoot: { newRoot: { $mergeObjects: [ { parentId: "$_id.parentId", year: { $toString: "$_id.year" }, month: { $toString: "$_id.month" }, day: { $toString: "$_id.day" } }, { $arrayToObject: "$nFields" } ] } } }, // 可选:按时间、parentId排序 { $sort: { year: 1, month: 1, day: 1, parentId: 1 } } ])
逻辑说明
先通过$objectToArray把嵌套的动态对象转成数组,再用$reduce拼接所有子对象的键值对,就能拿到每条数据里所有n:xx的字段和对应值;拆分数组后分组求和,再重新组装成你需要的扁平化输出结构,完全适配你给出的样例输入输出。
内容的提问来源于stack exchange,提问作者Jang
相关产品推荐
相关产品推荐

