So this is how my mongoose schema looks like:
JavaScript
x
9
1
const QuizModel = new mongoose.Schema({
2
quizId: { type: String, required: true, trim: true },
3
userId: { type: String, required: true, trim: true },
4
result: {
5
score: { type: Number, required: true},
6
time: { type: Number, required: true },
7
},
8
});
9
This is a quiz application so there are multiple documents with same userId
.
I am trying to make a query to build leaderboard and I came up with this.
JavaScript
1
4
1
const topUsers = await QuizModel.find({})
2
.sort({ "result.score": "desc", "result.time": "asc" })
3
.limit(10);
4
Now because I want to show only top 10 users, I have added .limit(10)
.
Now in these 10 documents, there is chance that all the 10 docs are of same user i.e. same userId
.
How do I prevent this and still get 10 documents with all unique userId
?
I don’t want a single user to occupy all 10 slots in leaderboard.
Example: User1 has 5 docs with above schema with scores 100, 95, 92, 90, 60 User2 has 5 docs with above schema with scores 95, 92, 90, 80, 60
Expected Output is:
JavaScript
1
19
19
1
[
2
{
3
quizId: "....",
4
userId: "user1",
5
result: {
6
score: 100,
7
time: "some_time"
8
}
9
},
10
{
11
quizId: "....",
12
userId: "user2",
13
result: {
14
score: 95,
15
time: "some_time"
16
}
17
}
18
]
19
Advertisement
Answer
You need $group along with $max in order to aggregate the scores per user, try:
JavaScript
1
15
15
1
const topUsers = await QuizModel.aggregate([
2
{
3
$group: {
4
_id: "$userId",
5
score: { $max: "$result.score" }
6
}
7
},
8
{
9
$sort: { score: 1 }
10
},
11
{
12
$limit: 10
13
}
14
])
15