如何用MongoDB聚合合并同key对象数组并计算总值
MongoDB按日期分组并合并channels同key值求和的聚合方案
原始数据
[ { "_id": ObjectId("65aa4921c767f95a70b8867f"), "creator": "Henry", "date": "2023-12-22", "channels": [ { "key": "HTV", "value": 1 } ] }, { "_id": ObjectId("65aa4921c767f95a70b8867f"), "creator": "Max", "date": "2023-12-23", "channels": [ { "key": "VTC", "value": 1 } ] }, { "_id": ObjectId("65aa4921c767f95a70b88689"), "creator": "John", "date": "2023-12-23", "channels": [ { "key": "VTC", "value": 2 }, { "key": "HTV", "value": 1 } ] } ]
需求说明
- 按
date字段分组 - 合并
channels数组中key相同的元素,计算对应value的总和 - 统计每组所有
value的总和(即Total字段)
现有代码片段
model.aggregate([ { $group: { _id: { date: '$date' }, Total: { $sum: { $sum: '$channels.value' } } } } ])
期望输出结果
[ { "date": "2023-12-22", "channels": [ { "key": "HTV", "value": 1 } ], "Total": 1 }, { "date": "2023-12-23", "channels": [ { "key": "VTC", "value": 3 // 1 + 2 }, { "key": "HTV", "value": 1 } ], "Total": 4 } ]
完整聚合解决方案
要实现需求,需要在现有代码基础上补充$unwind和多轮$group操作,完整的聚合管道如下:
model.aggregate([ // 1. 将每个文档的channels数组拆分为单个文档,便于按key分组计算 { $unwind: "$channels" }, // 2. 先按date和channels.key分组,计算每个key在对应日期下的value总和,同时累加总value { $group: { _id: { date: "$date", key: "$channels.key" }, keyTotal: { $sum: "$channels.value" }, totalSum: { $sum: "$channels.value" } } }, // 3. 再按date分组,将每个key的结果组装成channels数组,同时计算该日期的总Total { $group: { _id: "$_id.date", channels: { $push: { key: "$_id.key", value: "$keyTotal" } }, Total: { $sum: "$totalSum" } } }, // 4. 调整输出格式,将_id改为date字段,保持结构与期望一致 { $project: { _id: 0, date: "$_id", channels: 1, Total: 1 } } ])
步骤解释
$unwind:把每个文档中的channels数组拆分成独立的文档,每个文档包含一个channels对象,这样就能针对每个key单独进行求和操作。- 第一次
$group:以date和channels.key为组合分组键,计算每个key在对应日期下的value总和(keyTotal),同时累加该分组的总value(totalSum)。 - 第二次
$group:以date为分组键,将同一日期下的所有key结果通过$push组装成channels数组,同时把所有totalSum相加得到该日期的总Total。 $project:重新格式化输出文档,将_id替换为date字段,移除不必要的_id,确保输出结构与期望一致。
内容的提问来源于stack exchange,提问作者NHQUYEN
相关产品推荐
相关产品推荐

