MongoDB多阶段Group By未达预期输出,求正确聚合方案
MongoDB嵌套分组聚合解决方案
问题概述
需要对集合中的文档进行聚合分组,将相同顶层Id的文档合并为单文档,同时嵌套聚合用户及其关联的演唱会数据,形成指定的嵌套结构。
输入数据
[ { "Id": "Id1", "Title": "Title1", "User": { "Id": "Userid1", "Title": "User Title1", "Concerts": { "Id": "Concert3", "Title": "Concert title3", "Users": { "Id": "Userid1", "Title": "User Title Concert3" } } } }, { "Id": "Id1", "Title": "Title1", "User": { "Id": "Userid2", "Title": "User Title2", "Concerts": { "Id": "Concert1", "Title": "Concert title1", "Users": { "Id": "Userid2", "Title": "User Title2 Concert1" } } } }, { "Id": "Id1", "Title": "Title1", "User": { "Id": "Userid2", "Title": "User Title1", "Concerts": { "Id": "Concert4", "Title": "Concert title1", "Users": { "Id": "Userid2", "Title": "User Title2 Concert4" } } } } ]
期望输出
{ "Id": "Id1", "Title": "Title1", "User": [ { "Id": "Userid2", "Title": "User Title1", "Concerts": [ { "Id": "Concert4", "Title": "Concert title1", "Users": { "Id": "Userid2", "Title": "User Title2 Concert4" } }, { "Id": "Concert1", "Title": "Concert title1", "Users": { "Id": "Userid2", "Title": "User Title2 Concert1" } } ] }, { "Id": "Userid1", "Title": "User Title1", "Concerts": [ { "Id": "Concert1", "Title": "Concert title1", "Users": { "Id": "Userid1", "Title": "User Title Concert1" } }, { "Id": "Concert2", "Title": "Concert title1", "Users": { "Id": "Userid1", "Title": "User Title Concert2" } }, { "Id": "Concert3", "Title": "Concert title1", "Users": { "Id": "Userid1", "Title": "User Title Concert3" } } ] } ] }
尝试过的聚合管道
[ { $group: { _id: { "id": "$_id", "userId": "$User.Id", "ConcertsId": "$User.Concerts.Id" }, Title: { $first: "$Title" }, User: { $addToSet: "$User" } } }, { $group: { _id: { "id": "$_id", "userId": "$User.Id", "ConcertsId": "$User.Concerts.Id", "InnerUserId": "$User.Concerts.User.Id" }, Title: { $first: "$Title" }, User: { $addToSet: "$User" } } } ]
解答
1. Group By是实现该需求的正确选择
你的需求本质是多层级的分组聚合:先按顶层Id分组,再在每组内按用户Id分组,最后为每个用户聚合其关联的演唱会列表,$group(Group By)是完全适配这个需求的核心操作,只是之前的分组逻辑层级混乱,导致无法得到目标结构。
2. 正确的聚合管道实现
需要分三个阶段完成嵌套聚合:
[ // 第一阶段:去重并提取基础数据 { $group: { _id: { rootId: "$Id", userId: "$User.Id", concertId: "$User.Concerts.Id" }, rootTitle: { $first: "$Title" }, userTitle: { $first: "$User.Title" }, concert: { $first: "$User.Concerts" } } }, // 第二阶段:按用户聚合演唱会列表 { $group: { _id: { rootId: "$_id.rootId", userId: "$_id.userId" }, rootTitle: { $first: "$rootTitle" }, userTitle: { $first: "$userTitle" }, concerts: { $push: "$concert" } } }, // 第三阶段:按顶层ID聚合用户列表 { $group: { _id: "$_id.rootId", Title: { $first: "$rootTitle" }, User: { $push: { Id: "$_id.userId", Title: "$userTitle", Concerts: "$concerts" } } } }, // 可选:调整字段名匹配期望输出 { $project: { _id: 0, Id: "$_id", Title: 1, User: 1 } } ]
3. 管道逻辑说明
- 第一阶段:通过三重分组(顶层ID、用户ID、演唱会ID)避免重复数据,同时提取各层级的标题和演唱会详情。
- 第二阶段:基于第一阶段结果,按顶层ID和用户ID分组,用
$push将同一用户的所有演唱会组装成列表。 - 第三阶段:按顶层ID分组,将所有用户数据组装成列表,整理成目标字段结构。
- 可选的
$project阶段:将_id重命名为Id,移除冗余字段,完全匹配期望输出格式。
内容的提问来源于stack exchange,提问作者user2842284
相关产品推荐
相关产品推荐

