I have a mongoDB collection named students
with the fields grade
and name
.
I would like to create a query that will get up to 2 students from each grade inside my gradesList
.
In version MongoDB version 5.2. and above, you can use the $firstN
aggregation operator together with $group
like this:
const gradesList = [10, 11, 12]
db.students.aggregate([ { $match: { grade: { $in: gradesList } } },
{
$group: {
_id: '$grade',
name: {
$firstN: {
n: 2,
input: "$name"
}
}
}
},
{ $unwind: "$name" },
{ $project: { _id: 0, name: 1, grade: "$_id" } },
])
And this is the output:
[
{
name: 'Albert',
grade: 10
},
{
name: 'Tim',
grade: 10
},
{
name: 'Monika',
grade: 11
},
{
name: 'Mike',
grade: 11
},
{
name: 'Rich',
grade: 12
},
{
name: 'Beth',
grade: 12
},
]
However, in order to use $firstN
alongside MongoDB Atlas, you need to use a dedicated cluster which starts at around $60 a month, because the shared cluster tiers only support mongodb version 5.0, which don't support $firstN
.
Is there a way to accomplish the same objective with aggregation operators available in version 5.0?
CodePudding user response:
Only a small change is needed to be compatible with MongoDB version 5.0.
db.collection.aggregate([
{
"$match": {
"grade": {"$in": [10, 11, 12]}
}
},
{
"$group": {
"_id": "$grade",
"name": {"$push": "$name"}
}
},
{
"$set": {
"name": {"$slice": ["$name", 2]}
}
},
{"$unwind": "$name"},
{
"$project": {
"_id": 0,
"name": 1,
"grade": "$_id"
}
},
{
"$sort": {
"grade": 1,
"name": 1
}
}
])
Try it on mongoplayground.net.