Updating Documents in Mongoose

Mongoose has 4 different ways to update a document. Here's a list:

What's the difference between these 4 ways? Let's take a look at what each of these functions do.

Using save()

Below is an example of using save() to update Jon Snow's title.

const schema = new mongoose.Schema({ name : String , title : String }); const CharacterModel = mongoose.model( 'Character' , schema); const doc = await CharacterModel.create({ name : 'Jon Snow' , title : `Lord Commander of the Night's Watch` }); doc.title = 'King in the North' ; await doc.save();

This simple example has a couple nuances. First, save() is a method on a document, which means you must have a document to save. You need to either create() or use find() to get a document.

Second, Mongoose documents have change tracking. Under the hood, when you call doc.save() , Mongoose knows you set title and transforms your save() call into updateOne({ $set: { title } }) . Try running Mongoose with debug mode to see what queries Mongoose executes.

Using Model.updateOne() and Model.updateMany() , you can update the document without loading it from the database first. In the below example, the document with name = 'Jon Snow' is not in the Node.js process' memory when updateOne() is called.

await CharacterModel.updateOne({ name : 'Jon Snow' }, { title : 'King in the North' }); const doc = await CharacterModel.findOne(); doc.title;

updateMany() is similar. The difference between these two functions is that updateOne() will update at most one document, whereas updateMany() will update every document that matches the filter.

You should use save() rather than updateOne() and updateMany() where possible. However, Model.updateOne() and Model.updateMany() have a few advantages:

updateOne() is atomic. If you load a document using find() , it may change before you save() it.

is atomic. If you load a document using , it may change before you it. updateOne() doesn't require you to load the document into memory, which may give you better performance if your documents are huge.

The Document#updateOne() function is syntactic sugar for Model.updateOne() . If you already have the document in memory, doc.updateOne() structures a Model.updateOne() call for you.

const doc = await CharacterModel.findOne({ name : 'Jon Snow' }); const update = { title : 'King in the North' }; await doc.updateOne(update); const updatedDoc = await CharacterModel.findOne({ name : 'Jon Snow' }); updatedDoc.title;

Generally, Document#updateOne() is rarely useful. You're better off using save() and using Model.updateOne() for cases when save() is not flexible enough.

The Model.findOneAndUpdate() function or its variation Model.findByIdAndUpdate() behave similarly to updateOne() : they atomically update the first document that matches the first parameter filter . Unlike updateOne() , it gives you back the updated document.

const doc = await CharacterModel.findOneAndUpdate( { name : 'Jon Snow' }, { title : 'King in the North' }, { new : true } ); doc.title;

Summary

In general, you should use save() to update a document in Mongoose, unless you need an atomic update. Here's a summary of the key features of all 4 ways to update a document:

Want to become your team's MongoDB expert? "Mastering Mongoose" distills 8 years of hard-earned lessons building Mongoose apps at scale into 153 pages. That means you can learn what you need to know to build production-ready full-stack apps with Node.js and MongoDB in a few days. Get your copy!

More Mongoose Tutorials