Mongoose: findOneAndUpdate doesn't return updated document

node.jsMongodbMongoose

node.js Problem Overview


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.

node.js Solutions


Solution 1 - node.js

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);
});

Solution 2 - node.js

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' }

Solution 3 - node.js

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

Solution 4 - node.js

By default findOneAndUpdate returns the original document. If you want it to return the modified document pass an options object { new: true } to the function:

Cat.findOneAndUpdate({ age: 17 }, { $set: { name: "Naomi" } }, { new: true }, function(err, doc) {

});

Solution 5 - node.js

Mongoose maintainer here. You need to set the new option to true (or, equivalently, returnOriginal to false)

await User.findOneAndUpdate(filter, update, { new: true });

// Equivalent
await User.findOneAndUpdate(filter, update, { returnOriginal: false });

See Mongoose findOneAndUpdate() docs and this tutorial on updating documents in Mongoose.

Solution 6 - node.js

For whoever stumbled across this using ES6 / ES7 style with native promises, here is a pattern you can adopt...

const user = { id: 1, name: "Fart Face 3rd"};
const userUpdate = { name: "Pizza Face" };

try {
    user = await new Promise( ( resolve, reject ) => {
        User.update( { _id: user.id }, userUpdate, { upsert: true, new: true }, ( error, obj ) => {
            if( error ) {
                console.error( JSON.stringify( error ) );
                return reject( error );
            }

            resolve( obj );
        });
    })
} catch( error ) { /* set the world on fire */ }

Solution 7 - node.js

This is the updated code for findOneAndUpdate. It works.

db.collection.findOneAndUpdate(    
  { age: 17 },      
  { $set: { name: "Naomi" } },      
  {
     returnNewDocument: true
  }    
)

Solution 8 - node.js

If you want to return the altered document you need to set the option {new:true} API reference you can use Cat.findOneAndUpdate(conditions, update, options, callback) // executes

Taken by the official Mongoose API http://mongoosejs.com/docs/api.html#findoneandupdate_findOneAndUpdate you can use the following parameters

A.findOneAndUpdate(conditions, update, options, callback) // executes
A.findOneAndUpdate(conditions, update, options)  // returns Query
A.findOneAndUpdate(conditions, update, callback) // executes
A.findOneAndUpdate(conditions, update)           // returns Query
A.findOneAndUpdate()                             // returns Query

Another implementation thats is not expressed in the official API page and is what I prefer to use is the Promise base implementation that allow you to have .catch where you can deal with all your various error there.

    let cat: catInterface = {
		name: "Naomi"
	};

	Cat.findOneAndUpdate({age:17}, cat,{new: true}).then((data) =>{
		if(data === null){
			throw new Error('Cat Not Found');
		}
		res.json({ message: 'Cat updated!' })
		console.log("New cat data", data);
	}).catch( (error) => {
		/*
			Deal with all your errors here with your preferred error handle middleware / method
		 */
		res.status(500).json({ message: 'Some Error!' })
		console.log(error);
	});

Solution 9 - node.js

I know, I am already late but let me add my simple and working answer here

const query = {} //your query here
const update = {} //your update in json here
const option = {new: true} //will return updated document

const user = await User.findOneAndUpdate(query , update, option)

Solution 10 - node.js

Below shows the query for mongoose's findOneAndUpdate. Here new: true is used to get the updated doc and fields is used for specific fields to get.

eg. findOneAndUpdate(conditions, update, options, callback)

await User.findOneAndUpdate({
      "_id": data.id,
    }, { $set: { name: "Amar", designation: "Software Developer" } }, {
      new: true,
      fields: {
        'name': 1,
        'designation': 1
      }
    }).exec();

Solution 11 - node.js

2021 - Mongodb ^4.2.0 Update

This applies to the mongodb node driver, NOT mongoose.

It seems like the latest version of the Mongodb node driver uses the following syntax, if you are searching and updating using "collection.findOneAndUpdate":

.findOneAndUpdate(query, update, { returnDocument: 'after' | 'before' })

Couldn't find the answer here myself while searching, so posting this in case others are in the same situation.

Solution 12 - node.js

In some scenarios {new: true} is not working. Then you can try this.

{'returnNewDocument':true}

Solution 13 - node.js

export function newDocumentOnUpdatePlugin(schema) {
  schema.pre(
    ['update', 'findOneAndUpdate', 'updateOne', 'updateMany'],
    function (next) {
      this.setOptions({ new: true });
      next();
    },
  );
}

I have created this plugin if anyone need this functionality across the whole app and want to avoid repetition. Just use this as a global plugin

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
QuestionDreamsView Question on Stackoverflow
Solution 1 - node.jsXCSView Answer on Stackoverflow
Solution 2 - node.jsPedro Hoehl CarvalhoView Answer on Stackoverflow
Solution 3 - node.jsTsuneo YoshiokaView Answer on Stackoverflow
Solution 4 - node.jsuser2030471View Answer on Stackoverflow
Solution 5 - node.jsvkarpov15View Answer on Stackoverflow
Solution 6 - node.jsAssaf MoldavskyView Answer on Stackoverflow
Solution 7 - node.jsJobin MathewView Answer on Stackoverflow
Solution 8 - node.jsJonathan ThurftView Answer on Stackoverflow
Solution 9 - node.jsAljohn YamaroView Answer on Stackoverflow
Solution 10 - node.jsSourabh KhuranaView Answer on Stackoverflow
Solution 11 - node.jsCrucialView Answer on Stackoverflow
Solution 12 - node.jsPrakash HarvaniView Answer on Stackoverflow
Solution 13 - node.jsAll2PieView Answer on Stackoverflow