I have an array of students
in my Documents VirtualClass
and my goal is to create a roster with no duplication of students.
I want to match the VirtualClass
with the teacher and then $push
the student into an array.
Virtual Class Schema
const VirtualClassSchema = new Schema({
name: { type: String, required: true },
descriptionHeading: { type: String, required: true },
room: { type: String },
teacher: {
userId: { type: Schema.Types.ObjectId, ref: "User" },
name: { type: String },
profile_picture: { type: String }
},
students: [
{
userId: { type: Schema.Types.ObjectId, ref: "User" },
name: { type: String },
profile_picture: { type: String }
}
],
...
My current query is as follows
VirtualClass.aggregate([
{ $match: { "teacher.userId": user._id } },
{
$group: {
_id: null,
students: { $addToSet: "$students" }
}
}
])
Which returns:
[
{
"_id": null,
"students": [
[
{
"_id": "5e84d1a1ab3ebf54283b8cb2",
"userId": "5dd27452592f600900235945",
"name": "student zero",
"profile_picture": "https://productionstemulistorage.blob.core.windows.net/stemuli/profile-picture-6e609f3b-44cb-44c0-888a-1b6767e3072d"
}
],
[
{
"_id": "5e84d1a1ab3ebf54283b8cb4",
"userId": "5dd27452592f600900235945",
"name": "student zero",
"profile_picture": "https://productionstemulistorage.blob.core.windows.net/stemuli/profile-picture-6e609f3b-44cb-44c0-888a-1b6767e3072d"
}
]
]
}
]
Expected results:
_id: null,
"students":
[
{
"_id": "5e84d1a1ab3ebf54283b8cb4",
"userId": "5dd27452592f600900235945",
"name": "student zero",
"profile_picture": "https://productionstemulistorage.blob.core.windows.net/stemuli/profile-picture-6e609f3b-44cb-44c0-888a-1b6767e3072d"
}
]
Thank you!
The indexof() method in Javascript is one of the most convenient ways to find out whether a value exists in an array or not. The indexof() method works on the phenomenon of index numbers. This method returns the index of the array if found and returns -1 otherwise.
To check if a TypeScript array contains an object:Pass a function to the Array. find() method. Check whether the identifier of the object is equal to a specific value and return true if it is. Array.
You could use exclusion to remove the id from the document before sending it to $addToSet. Also your student is array so you would need $unwind
.
Something like
VirtualClass.aggregate([
{$match:{"teacher.userId": user._id}},
{$project:{"students._id": 0}},
{$unwind: "$students"},
{$group:{
_id: null,
students: {$addToSet:"$students"}
}}
])
example here - https://mongoplayground.net/p/zULrmihM03z
Output
[
{
"_id": null,
"students": [
{
"name": "student zero",
"profile_picture": "https://productionstemulistorage.blob.core.windows.net/stemuli/profile-picture-6e609f3b-44cb-44c0-888a-1b6767e3072d",
"userId": "5dd27452592f600900235945"
}
]
}
]
Another alternative would be to set _id to false so mongoose will not generate any id for student.
Something like
students: [
{
userId: { type: Schema.Types.ObjectId, ref: "User" },
name: { type: String },
profile_picture: { type: String },
_id:false
}
],
You can then use aggregation query without the exclusion.
VirtualClass.aggregate([
{$match:{"teacher.userId": user._id}},
{$unwind: "$students"},
{$group:{
_id: null,
students: {$addToSet:"$students"}
}}
])
You need to $unwind
and then $project
to remove _id
before $group
in your aggregate function.
Code:
[
{
"$match": {
"teacher.userId": 1
}
},
{
"$unwind": "$students"
},
{
"$project": {
"students._id": 0
}
},
{
"$group": {
"_id": null,
"students": {
"$addToSet": "$students"
}
}
}
]
Example code and Pipeline Explanation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With