如何使用MongoDB对集合分组并求和对象属性生成计算字段
MongoDB按duelId分组并统计选手总得分的实现方案
该需求可通过MongoDB聚合管道完全实现,具体方案如下:
需求说明
按duelId字段对比赛记录分组,保留分组内所有原始比赛记录,同时统计分组内每个选手的battlesWon总和作为新增得分字段。
现有数据结构
{ "matches": [ { "secondParticipant": {"name": "Maria","battlesWon": 2}, "firstParticipant": {"name": "Fabio","battlesWon": 1}, "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a102" }, { "secondParticipant": {"name": "Fabio","battlesWon": 1}, "firstParticipant": {"name": "Maria","battlesWon": 1}, "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a102" }, { "secondParticipant": {"name": "Luiz","battlesWon": 1}, "firstParticipant": {"name": "Jose","battlesWon": 1}, "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a666" } ] }
实现思路
- 若原始文档外层嵌套
matches数组,先用$unwind将数组拆分为独立的单条比赛文档 $group阶段按duelId分组,用$push保留同组所有原始比赛记录,同时收集所有参赛选手的姓名和得分- 展平收集到的选手数据,按选手姓名分组求和生成总得分对象
- 按需调整输出结构匹配预期格式
完整聚合查询代码
假设集合名为duels,聚合语句如下:
db.duels.aggregate([ // 展开外层matches数组,若集合直接存储单条比赛记录可删除该阶段 { $unwind: "$matches" }, // 按duelId分组 { $group: { _id: "$matches.duelId", matchList: { $push: "$matches" }, allPlayers: { $push: { $concatArrays: [ [ { name: "$matches.firstParticipant.name", score: "$matches.firstParticipant.battlesWon" } ], [ { name: "$matches.secondParticipant.name", score: "$matches.secondParticipant.battlesWon" } ] ] } } } }, // 展平所有选手数组 { $addFields: { allPlayers: { $reduce: { input: "$allPlayers", initialValue: [], in: { $concatArrays: ["$$value", "$$this"] } } } } }, // 计算选手总得分 { $addFields: { score: { $arrayToObject: { $map: { input: { $setUnion: "$allPlayers.name" }, as: "playerName", in: { k: "$$playerName", v: { $sum: { $map: { input: { $filter: { input: "$allPlayers", cond: { $eq: ["$$this.name", "$$playerName"] } } }, in: "$$this.score" } } } } } } } } }, // 默认输出结构化结果,如需匹配示例数组格式可替换为下方注释的阶段 { $project: { _id: 0, duelId: "$_id", matchList: 1, score: 1 } } /* 如需输出示例中的数组结构,替换上面的$project阶段为以下代码: { $project: { _id: 0, result: { $concatArrays: ["$matchList", [ { score: "$score" } ]] } } } */ ])
输出结果说明
默认输出的结构化结果示例:
{ "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a102", "matchList": [ { "secondParticipant": {"name": "Maria","battlesWon": 2}, "firstParticipant": {"name": "Fabio","battlesWon": 1}, "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a102" }, { "secondParticipant": {"name": "Fabio","battlesWon": 1}, "firstParticipant": {"name": "Maria","battlesWon": 1}, "duelId": "6c3e532d-3c0e-4438-8289-c86a4a51a102" } ], "score": {"Fabio": 2, "Maria": 3} }
若使用替换后的数组结构输出,完全匹配你给出的预期格式。
内容的提问来源于stack exchange,提问作者Daywison Ferreira Leal
相关产品推荐
相关产品推荐

