Reputation: 861
I have a mongodb document, let's say having the schema
class: String,
class_teacher: String,
students: [
{
student: String,
marks: number
}
]
In the above example if I push a new student to the collection, it'll generate a _id
for each student and I am doing it by using the update query for the entire document.
Is it the right way to do it?
If yes, how can I get the _id for each student as soon as I push the student object?
After some time, if I want to update the marks of a single student, what is the best way to do it??
Upvotes: 0
Views: 91
Reputation: 151112
In nice mode, I'll answer all of your "questions", here is some demonstration code:
var mongoose = require("mongoose"),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var classSchema = new Schema({
class: String,
teacher: String,
students: [{ student: String, marks: Number }]
});
var Class = mongoose.model("Class", classSchema);
var myclass = new Class();
myclass.students.push(
{ student: "bill", marks: 10 },
{ student: "ted", marks: 5 }
);
console.log("Whole:\n %s\n",myclass);
console.log("Last added _id: %s\n",myclass.students.slice(-1)[0]._id);
myclass.save(function(err,myclass) {
if (err) throw err;
Class.findOneAndUpdate(
{ "students.student": "ted" },
{ "$set": { "students.$.marks": 7 } },
function(err,doc) {
if (err) throw err;
console.log(doc);
}
);
});
So overall:
Sure not a problem, even though you might find defining your schema for "Student" separately to be a bit more maintainable in the long run:
var studenSchema = new Schema({
student: String,
marks: Number
});
var classSchema = new Schema({
class: String,
teacher: String,
students: [studentSchema]
});
Well the last added element in the array when you modify this way can just be pulled off with .slice()
, then you can get the last _id
value.
console.log("Last added _id: %s\n",myclass.students.slice(-1)[0]._id);
Updating marks can be best done with .findOneAndUpdate()
or a similar operation. Here you query to match the document and array element and update the correct one with use of the positional $
operator:
Class.findOneAndUpdate(
{ "students.student": "ted" },
{ "$set": { "students.$.marks": 7 } },
function(err,doc) {
if (err) throw err;
console.log(doc);
}
);
This also returns the document that is modified so you can see the changes. For "bulk" operations you would use the .update()
method along with the "multi" option.
You can also "add" new students to the array using the $push
operator, and just as before the document is returned with the method shown, so you could also apply getting the new _id
value that way:
Class.findOneAndUpdate(
{ "students.student": "ted" },
{ "$push": { "students": { "student": "sally", "marks": 4 }} },
function(err,doc) {
if (err) throw err;
console.log("Whole:\n %s", doc);
console.log("Last added _id: %s\n",doc.students.slice(-1)[0]._id);
}
);
And that produces results like this:
Whole:
{ _id: 53bc9844c1cbd4d24eac8db6,
__v: 0,
students:
[ { student: 'bill', marks: 10, _id: 53bc9844c1cbd4d24eac8db7 },
{ student: 'ted', marks: 7, _id: 53bc9844c1cbd4d24eac8db8 },
{ student: 'sally', marks: 4, _id: 53bca6c346d93b32624e5af4 } ] }
Last added id: 53bca6c346d93b32624e5af4
If you need other schema validation features or other hooks on field values then you will need to individually .find()
documents, modify in code and then .save()
. But these are the alternate approaches, which usually create less "wire traffic" than dealing with whole documents.
Upvotes: 2