[{
score: 7000,
mapId: 1,
profileId: 12
}, {
score: 400,
mapId: 1,
profileId: 6
}, {
score: 12000,
mapId: 1,
profileId: 12
}, {
score: 5000,
mapId: 1,
profileId: 12
}, {
score: 120,
mapId: 1,
profileId: 8
}]
I have a game’s REST API and users send their map scores to a route and I save them in Mongo, users can have multiple score entries for multiple mapIds or for one mapId.
JSON above is a result of all documents, with score, mapId and profileId. You can see a profileId can have multiple scores for a mapId, I’m asking the best query for getting the top 3 best scores, but there cant be scores from multiple profileIds, which means it must be a profile’s highest score only. The result should look like this:
[{
score: 12000,
mapId: 1,
profileId: 12
}, {
score: 400,
mapId: 1,
profileId: 6
}, {
score: 120,
mapId: 1,
profileId: 8
}]
I have tried following aggregation to get mapId: 1
leaderboard but scores can get mixed up and the lowest score weirdly sometimes turns into the highest score.
this.db.aggregate([
{ $match: { mapId: 1 } },
{ $group: { _id: "$profileId", score: { $max: "$score" }, root: { $first: "$$ROOT" } } },
{ $sort: { score: -1 } },
{ $limit: 3 }
]);
I’m looking for something that does it all easy without anything extra or dumb.
2
Answers
To be honest your query is already good enough i think. You should remove the
root : {$first :"$$ROOT"}
because the$first
operator won’t always give you the doc with the highest score.You should add some
$set
and$unset
stage for your results to match the expected output.You can use
$setWindowFields
to compute$rank
for each profileId. You can then takerank: 1
to get the top score for each player. Finally, do a$sort
+$limit
to get the top 3 scores.Mongo Playground
Thanks @Joe and @nimrod serok for the constructive feedbacks.