Why can't you modify the data returned by a Mongoose Query (ex: findById)
node.jsMongoosenode.js Problem Overview
When I try to change any part of the data returned by a Mongoose Query it has no effect.
I was trying to figure this out for about 2 hours yesterday, with all kinds of _.clone()
s, using temporary storage variables, etc. Finally, just when I though I was going crazy, I found a solution. So I figured somebody in the future (fyuuuture!) might have the save issue.
Survey.findById(req.params.id, function(err, data){
var len = data.survey_questions.length;
var counter = 0;
_.each(data.survey_questions, function(sq){
Question.findById(sq.question, function(err, q){
sq.question = q; //has no effect
if(++counter == len) {
res.send(data);
}
});
});
});
node.js Solutions
Solution 1 - node.js
For cases like this where you want a plain JS object instead of a full model instance, you can call lean()
on the query chain like so:
Survey.findById(req.params.id).lean().exec(function(err, data){
var len = data.survey_questions.length;
var counter = 0;
_.each(data.survey_questions, function(sq){
Question.findById(sq.question, function(err, q){
sq.question = q;
if(++counter == len) {
res.send(data);
}
});
});
});
This way data
is already a plain JS object you can manipulate as you need to.
Solution 2 - node.js
I think the Mongoose documentation doesn't make this clear enough, but the data returned in the query (although you can res.send() it) is actually a Mongoose Document object, and NOT a JSON object. But you can fix this with one line...
Survey.findById(req.params.id, function(err, data){
var len = data.survey_questions.length;
var counter = 0;
var data = data.toJSON(); //turns it into JSON YAY!
_.each(data.survey_questions, function(sq){
Question.findById(sq.question, function(err, q){
sq.question = q;
if(++counter == len) {
res.send(data);
}
});
});
});
Solution 3 - node.js
I was using mongoose and here are the workaround I did to resolve it:
1): Mongoose returns MongooseDocument objects and not plain JSON objects. So use the lean() method on object which will convert it into JSON, and from there you can change it
const leanDoc = await MyModel.findOne().lean();
---------------------------------OR---------------------------------
2): Create a deep copy of the result returned by find query as shown below
Books.find({}).then(books => {
books = JSON.parse(JSON.stringify(books));
//now you can update the books object
}