如何用MongoDB聚合实现按用户分组并展示各游戏得分列表?
问题
我有一个将游戏玩法数据存入MongoDB的API,该API接收gameId、userId和score参数,数据示例如下:
[ { "gameId": "G1", "userId": "U22", "score": 420 }, { "gameId": "G2", "userId": "U22", "score": 10 }, { "gameId": "G1", "userId": "U22", "score": 80 }, { "gameId": "G1", "userId": "U25", "score": 400 } ]
当游戏结束('Game Over')时会创建游戏得分文档,用户可在同一天内多次游玩。
目前我已通过以下聚合查询实现游戏排行榜:
db.plays.aggregate([ { $group: { _id: '$userId', played: { $sum: 1 }, score: { $sum: '$score' } } }, { $limit: 100 }, { $sort: { score: -1 } } ]);
查询输出如下:
[ { "_id": "U22", "played": 3, "score": 510 }, { "_id": "U25", "played": 1, "score": 400 } ]
现在我希望得到包含用户游玩游戏数组的结果,期望输出如下:
[ { "_id": "U22", "played": [ { "gameId": "G1", "score": 500 }, { "gameId": "G2", "score": 10 } ], "score": 510 }, { "_id": "U25", "played": [ { "gameId": "G1", "score": 400 } ], "score": 400 } ]
请问如何实现该需求?
解决方案
调整聚合管道,通过两层分组来实现需求,具体查询如下:
db.plays.aggregate([ // 按用户+游戏分组,计算单游戏总得分 { $group: { _id: { userId: "$userId", gameId: "$gameId" }, gameScore: { $sum: "$score" } } }, // 按用户分组,整理游戏列表并计算总得分 { $group: { _id: "$_id.userId", played: { $push: { gameId: "$_id.gameId", score: "$gameScore" } }, score: { $sum: "$gameScore" } } }, // 按总得分降序排序 { $sort: { score: -1 } }, // 限制返回前100条结果 { $limit: 100 } ]);
逻辑说明:
- 第一层
$group:以userId和gameId的组合作为分组键,统计每个用户在单款游戏中的累计得分gameScore。 - 第二层
$group:以userId为分组键,用$push将每个游戏的gameId和gameScore组装成对象存入played数组;同时用$sum累加所有游戏的得分,得到用户的总得分score。 $sort:按用户总得分从高到低排序,符合排行榜的需求。$limit:限制返回前100条结果,与原查询逻辑保持一致。
内容的提问来源于stack exchange,提问作者Lahiru Supun
相关产品推荐
相关产品推荐

