Why can't you modify the data returned by a Mongoose Query (ex: findById)

node.jsMongoose

node.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
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionToliView Question on Stackoverflow
Solution 1 - node.jsJohnnyHKView Answer on Stackoverflow
Solution 2 - node.jsToliView Answer on Stackoverflow
Solution 3 - node.jsvivek sharmaView Answer on Stackoverflow