MongoDB聚合嵌套数组事件出现次数,重组原结构遇阻求助
统计嵌套数组中事件出现次数并还原原结构问题
需求描述
统计嵌套数组statuses.events_count中各事件的出现次数,同时保留原文档的结构。
输入示例
[ { "statuses": [ { "status": "allowed", "count": 3, "events_count": [ "2001", "1001", "1001" ] } ], "date": "2022-09-10 15:00", "_id": "2022-09-10 15:00" } ]
期望输出
[ { "statuses": [ { "status": "allowed", "count": 3, "events_count": [ {"type": "2001", "count": 1}, {"type": "1001", "count": 2} ] } ], "date": "2022-09-10 15:00", "_id": "2022-09-10 15:00" } ]
尝试的聚合管道
db.collection.aggregate([ { "$unwind": "$statuses" }, { "$unwind": "$statuses.events_count" }, { "$group": { "_id": { "event_count": "$statuses.events_count", "status": "$statuses.status", "date": "$date", "count": "$statuses.count" }, "occurences": { "$sum": 1 } } } ])
当前输出
[ { "_id": { "count": 3, "date": "2022-09-10 15:00", "event_count": "2001", "status": "allowed" }, "occurences": 1 }, { "_id": { "count": 3, "date": "2022-09-10 15:00", "event_count": "1001", "status": "allowed" }, "occurences": 2 } ]
问题
重新分组回原结构时遇到困难,按date分组并推回statuses数组后,得到两个status为allowed的条目,无法合并成一个。
解决方案
需要通过多轮分组逐步还原原结构,完整聚合管道如下:
db.collection.aggregate([ // 展开外层的statuses数组 { "$unwind": "$statuses" }, // 展开每个status下的events_count数组 { "$unwind": "$statuses.events_count" }, // 第一步分组:统计每个事件类型的出现次数,保留关联元数据 { "$group": { "_id": { "event_type": "$statuses.events_count", "status": "$statuses.status", "date": "$date", "status_count": "$statuses.count", "doc_id": "$_id" }, "event_count": { "$sum": 1 } } }, // 第二步分组:将同一状态下的统计事件合并为events_count数组 { "$group": { "_id": { "status": "$_id.status", "date": "$_id.date", "status_count": "$_id.status_count", "doc_id": "$_id.doc_id" }, "events_count": { "$push": { "type": "$_id.event_type", "count": "$event_count" } } } }, // 第三步分组:将状态对象合并回statuses数组,还原原结构 { "$group": { "_id": "$_id.doc_id", "date": { "$first": "$_id.date" }, "statuses": { "$push": { "status": "$_id.status", "count": "$_id.status_count", "events_count": "$events_count" } } } }, // 确保输出字段与原文档一致 { "$project": { "_id": "$_id", "date": 1, "statuses": 1 } } ])
逻辑说明
- 第一轮分组:精准统计每个事件类型在对应状态、日期下的出现次数,同步保留所有需要复用的元数据;
- 第二轮分组:将同一状态下的所有统计结果整理成
events_count数组,形成单个完整的状态对象; - 第三轮分组:按文档
_id分组,将状态对象合并回statuses数组,完全还原原文档结构; - $project阶段:确保输出字段与原文档匹配,避免多余字段干扰。
内容的提问来源于stack exchange,提问作者Shai
相关产品推荐
相关产品推荐

