Promises in Mongoose

Mar 23, 2020

Mongoose has built-in support for promises. In Mongoose 5, async operations like .save() and .find().exec() return a promise unless you pass a callback.

const Model = mongoose.model('Test', Schema({
  name: String
}));

const doc = new Model({ name: 'Neo' });

const promise = doc.save();
promise instanceof Promise; // true

const res = doc.save(function callback(err) {
  /*...*/
});
res; // undefined

The mongoose.Promise Property

The Mongoose singleton has a Promise property that you can use to set the promise library Mongoose uses. For example, you can make Mongoose use the popular Bluebird promise library:

const Bluebird = require('bluebird');

// Make Mongoose use Bluebird instead of built-in promises.
mongoose.Promise = Bluebird;

const doc = new Model({ name: 'Neo' });

const promise = doc.save();
promise instanceof Promise; // false
promise instanceof Bluebird; // true

If you haven't upgraded to Mongoose 5 yet, you might see the below deprecation warning in Mongoose 4.x:

WARNING: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead

To resolve that deprecation warning, you would add the below code:

mongoose.Promise = global.Promise;

That's because one of the breaking changes in Mongoose 5 was switching to using Node.js' native promises. Mongoose 4 was released before ES6, so it had its own promise implementation that was slightly different from native JavaScript promises.

If you see mongoose.Promise = global.Promise in code that uses Mongoose 5, please delete it. Mongoose 5 uses native promises by default, so that code does nothing in Mongoose 5.

Queries are not Promises

While save() returns a promise, functions like Mongoose's find() return a Mongoose Query.

const query = Model.find();

query instanceof Promise; // false
query instanceof mongoose.Query; // true

Mongoose queries are thenables. In other words, queries have a then() function that behaves similarly to the Promise then() function. So you can use queries with promise chaining and async/await.

// Using queries with promise chaining
Model.findOne({ name: 'Mr. Anderson' }).
  then(doc => Model.updateOne({ _id: doc._id }, { name: 'Neo' })).
  then(() => Model.findOne({ name: 'Neo' })).
  then(doc => console.log(doc.name)); // 'Neo'

// Using queries with async/await
const doc = await Model.findOne({ name: 'Neo' });
console.log(doc.name); // 'Neo'

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