MongoDB按日期与类型嵌套分组聚合及卡路里求和实现咨询
MongoDB嵌套分组聚合需求与解决方案
问题背景
我在MongoDB中有一个名为entries的集合,数据结构如下:
[ { "date": "Mon Jul 07 2022 17:15:19", "name": "Banana", "calories": 100, "mealID": "62d55d4de4c92d6de31e22ad", "type": "Lunch" }, { "date": "Mon Jul 07 2022 17:15:19", "name": "Buger", "calories": 300, "mealID": "62d55d4de4c92d6de31e22ad", "type": "Lunch" }, { "date": "Mon Jul 07 2022 17:15:19", "name": "Coffee", "calories": 120, "mealID": "62d55d4de4c92d6de31e22", "type": "Break fast" }, { "date": "Mon Jul 07 2022 17:15:19", "name": "Omlet", "calories": 70, "mealID": "62d55d4de4c92d6de31e22ad", "type": "Dinner" } ]
期望结果
需要对该集合执行聚合操作,按date和type(Lunch/Break fast/Dinner)进行嵌套分组,同时按日期统计总卡路里,最终结果格式如下:
[ { _id: "Mon Jul 07 2022 17:15:19", entriesForTheDay: { "Dinner": { entries: [ {name: "Omlet", calories: 70}, ], count: 1, }, "Break fast": { entries: [ {name: "Coffee", calories: 120}, ], count: 1, }, "Lunch": { entries: [ {name: "Banana", calories: 100}, {name: "Buger", calories: 300}, ], count: 2, } }, totalCaloriesForThDay: 590 } ]
尝试的代码
我尝试了以下聚合代码,但不清楚如何按$type字段进行分组:
[ {$group: {_id: '$date', entries: { $push: { entry: { name: '$name', calories: '$calories', type: '$type' }, } }, count: { "$sum": 1 } } }, ]
解决方案
要实现嵌套分组并生成目标格式,需要分三步构建聚合管道:
- 按
date+type复合键分组,统计每个餐型的条目、数量和卡路里; - 按
date聚合,将各餐型数据整理为键值对数组; - 将数组转为嵌套对象,同时计算当日总卡路里。
完整的聚合代码如下:
db.entries.aggregate([ // 第一步:按日期+餐型分组,收集条目、统计数量和餐型卡路里 { $group: { _id: { date: "$date", type: "$type" }, entries: { $push: { name: "$name", calories: "$calories" } }, count: { $sum: 1 }, typeCalories: { $sum: "$calories" } } }, // 第二步:按日期分组,整理餐型数据为键值对数组,累加当日总卡路里 { $group: { _id: "$_id.date", entriesForTheDay: { $push: { k: "$_id.type", v: { entries: "$entries", count: "$count" } } }, totalCaloriesForThDay: { $sum: "$typeCalories" } } }, // 第三步:将键值对数组转为嵌套对象,匹配目标格式 { $addFields: { entriesForTheDay: { $arrayToObject: "$entriesForTheDay" } } } ])
代码说明
- 第一层
$group:用复合_id确保每个日期下的不同餐型单独聚合,收集对应条目、统计餐型内的条目数量和卡路里总和; - 第二层
$group:按日期聚合所有餐型数据,用$push生成包含餐型名称(k)和餐型详情(v)的数组,同时累加所有餐型的卡路里得到当日总摄入; $addFields阶段:通过$arrayToObject将数组结构的餐型数据转为嵌套对象,完全匹配期望的entriesForTheDay格式。
内容的提问来源于stack exchange,提问作者Wimal Weerawansa
相关产品推荐
相关产品推荐

