Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose: findOneAndUpdate doesn't return updated document

Below is my code

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', {
    name: String,
    age: {type: Number, default: 20},
    create: {type: Date, default: Date.now} 
});

Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}},function(err, doc){
    if(err){
        console.log("Something wrong when updating data!");
    }

    console.log(doc);
});

I already have some record in my mongo database and I would like to run this code to update name for which age is 17 and then print result out in the end of code.

However, why I still get same result from console(not the modified name) but when I go to mongo db command line and type "db.cats.find();". The result came with modified name.

Then I go back to run this code again and the result is modified.

My question is: If the data was modified, then why I still got original data at first time when console.log it.

like image 669
Dreams Avatar asked Sep 27 '15 18:09

Dreams


People also ask

What does findOneAndUpdate return Mongoose?

By default, findOneAndUpdate() returns the document as it was before update was applied. You should set the new option to true to return the document after update was applied.

What is the difference between findOneAndUpdate and UpdateOne?

findOneAndUpdate returns a document whereas updateOne does not (it just returns the _id if it has created a new document).

Is findOneAndUpdate Atomic?

According to these docs , single write transactions are atomic. So with findOneAndUpdate, this would indeed be atomic.

Does update call save in Mongoose?

When you create an instance of a Mongoose model using new , calling save() makes Mongoose insert a new document. If you load an existing document from the database and modify it, save() updates the existing document instead.


3 Answers

Why this happens?

The default is to return the original, unaltered document. If you want the new, updated document to be returned you have to pass an additional argument: an object with the new property set to true.

From the mongoose docs:

Query#findOneAndUpdate

Model.findOneAndUpdate(conditions, update, options, (error, doc) => {   // error: any errors that occurred   // doc: the document before updates are applied if `new: false`, or after updates if `new = true` }); 

Available options

  • new: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)

Solution

Pass {new: true} if you want the updated result in the doc variable:

//                                                         V--- THIS WAS ADDED Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}}, {new: true}, (err, doc) => {     if (err) {         console.log("Something wrong when updating data!");     }      console.log(doc); }); 
like image 90
XCS Avatar answered Nov 03 '22 10:11

XCS


For anyone using the Node.js driver instead of Mongoose, you'll want to use {returnOriginal:false} instead of {new:true}.

2021 - Mongodb ^4.2.0 Update
{ returnDocument: 'after' }

like image 22
Pedro Hoehl Carvalho Avatar answered Nov 03 '22 10:11

Pedro Hoehl Carvalho


So, "findOneAndUpdate" requires an option to return original document. And, the option is:

MongoDB shell

{returnNewDocument: true}

Ref: https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/

Mongoose

{new: true}

Ref: http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

Node.js MongoDB Driver API:

{returnOriginal: false}

2021 - Mongodb ^4.2.0 Update
{ returnDocument: 'after' }

Ref: http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#findOneAndUpdate

like image 24
Tsuneo Yoshioka Avatar answered Nov 03 '22 10:11

Tsuneo Yoshioka