如何在MongoDB中分组多轮高尔夫赛事数据生成排行榜?
解决多轮高尔夫比赛的排行榜统计问题
嘿,我来帮你搞定这个多轮成绩统计的需求!你之前用循环的思路方向是对的,但MongoDB本身提供的聚合框架,能更高效、简洁地实现分组累加需求,不用手动处理数组遍历和更新的繁琐逻辑。
核心思路
我们需要完成这几个关键步骤:
- 先筛选出目标
matchId对应的所有轮次ID(从rounds集合) - 基于这些轮次ID,从
roundScores中获取所有相关的球员成绩 - 按
playerId分组,累加每个球员的toPar和points - 按
toPar升序排序(高尔夫中toPar越低成绩越好),生成最终排行榜
正确的MongoDB聚合查询代码
直接用聚合管道就能一步到位,比你写的循环高效太多:
db.roundScores.aggregate([ // 第一步:关联rounds集合,匹配对应matchId的轮次 { $lookup: { from: "rounds", localField: "roundId", foreignField: "_id", as: "roundInfo" } }, // 过滤出目标matchId的成绩记录 { $match: { "roundInfo.matchId": matchId } }, // 展开关联的轮次信息数组(lookup返回的是数组,需转为单条记录) { $unwind: "$roundInfo" }, // 按playerId分组,累加toPar和points总和 { $group: { _id: "$playerId", totalToPar: { $sum: "$toPar" }, totalPoints: { $sum: "$points" } } }, // 按总toPar升序排序(成绩越好越靠前) { $sort: { totalToPar: 1 } }, // 可选:调整输出字段名,让结果更直观 { $project: { playerId: "$_id", totalToPar: 1, totalPoints: 1, _id: 0 } } ])
代码逐段解释
$lookup:将roundScores和rounds集合通过roundId关联,拿到每个成绩对应的赛事matchId信息。$match:只保留目标赛事下的成绩记录,过滤掉无关数据。$unwind:把$lookup返回的数组型轮次信息展开为单条记录,方便后续分组操作。$group:核心步骤——按playerId分组,用$sum算子自动累加每个球员的toPar和points总和。$sort:按照累加后的totalToPar升序排序,符合高尔夫的排名规则(低于标准杆越多,排名越靠前)。$project:可选步骤,重命名字段(比如把默认的_id改成playerId),让输出结果更易读。
针对你之前循环代码的优化说明
你之前的循环思路需要手动遍历所有轮次和成绩,还要自己在数组中查找对应球员更新数据,不仅代码繁琐,而且数据量较大时效率会很低。用聚合框架的话,这些逻辑都由MongoDB引擎优化处理,代码更简洁,执行效率也更高。
示例数据验证
用你给出的示例数据测试,最终输出结果会是:
[ { "playerId": "54354245566", "totalToPar": 1, "totalPoints": 54 }, { "playerId": "12653426518", "totalToPar": 4, "totalPoints": 56 } ]
(注:你给出的期望结果中points数值看起来可能是笔误,按示例数据累加应为31+23=54和27+29=56)
内容的提问来源于stack exchange,提问作者Mansa
相关产品推荐
相关产品推荐

