Reputation: 2216
I want to define a one-to-many relationship between my Student model and my Formation model: 1 student belongs to 1 formation and a formation can be composed of N students.
My needs are:
So I wrote:
let student = new Schema({
firstName: {
type: String
},
lastName: {
type: String
},
formation : {
type: Schema.Types.ObjectId,
ref: 'Formation'
}
});
let formation = new Schema({
title: {
type: String
},
students: [{ type: Schema.Types.ObjectId, ref: 'Student' }]
}
When I'm searching for documentation about the one-to-many relation with mongodb/mongoose, I'm surprised to see that when I want to create a Student document (and add it to a formation), I must not only set its "formation" field with the formation id and also push it to the formation document "students" field.
Does it imply that when I want to replace the formation of a student with another formation, I'll need to 1/ update its formation field 2/ remove myself the student id from the formation "students" field and re-add it to the students field of the new formation?
It seems a little redundant to me. Am I missing something?
Upvotes: 1
Views: 500
Reputation: 712
It is in fact redundant because the way you have defined your schemas is redundant. The array of students should be a property of the formation, but not the other way around. Subdocuments can be searched like normal collections. If you change your schema to:
let student = new Schema({
firstName: {
type: String
},
lastName: {
type: String
}
});
let formation = new Schema({
title: {
type: String
},
students: [{ type: Schema.Types.ObjectId, ref: 'Student' }]
}
You should be able to accomplish your needs with fairly short commands. Assuming formations and students are your collection names:
1: Generating a student and saving both the formation and student documents.
var stud = new student({name: "Sally"}); //Assuming you modeled to student
stud.save(function (err, student) {
formations.findOne({}, function (err, form) { //Dont know how you find formations, I assume you know
form.students.push(stud._id);
form.save(callback);
}
});
2. Retrieving the formation of a student with a given ID:
formations.findOne({"students" : { $elemMatch: {_id: id}}}, function (err, doc) {})
Even moving a student is relatively simple.
formNew.students.push (
formOld.students.pop(formOld.students.indexOf(formOld.students.findOne(
//elemMatch like above
)))
Sorry about the weird formatting.
Upvotes: 1
Reputation: 6153
Having students
on the Formation model is both bad practice and redundant. Potentially infinite arrays are a poor design as they can lead to hitting document size limits. In regards to being redundant, you only have two queries in this situation:
1) You have a student
in memory, and you want to find their formation:
Formation.findOne({_id: student.formation},callback);
2) You have a formation
in memory, and want to find all students in that formation:
Student.find({formation: formation._id}, callback);
Neither of which require having students
on the Formation schema.
Upvotes: 2