Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose promises documentation says queries are not promises?

From the docs (Mongoose v5.4.1, latest version):

Mongoose async operations, like .save() and queries, return thenables. This means that you can do things like MyModel.findOne({}).then()

second parapraph from the docs states:

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience.

What Javascript MDN webpage states:

The then() method returns a Promise.

Does this mean that mongoose has another kind of implementation for async functions where they reserved the then keyword for the result of the async action?

In other words, they act like promises but are not JS promises?

like image 865
Eugen Sunic Avatar asked Dec 29 '18 15:12

Eugen Sunic


People also ask

Are Mongoose queries promises?

Mongoose queries are not promises. They have a . then() function for co and async/await as a convenience. However, unlike promises, calling a query's .

Does Mongoose connect return a Promise?

You don't handle a Promise with a callback: mongoose call you're callback if provided, otherwise it return the Promise.

What is $in in mongoose?

The value of the $in operator is an array that contains few values. The document will be matched where the value of the breed field matches any one of the values inside the array.

What is fully fledged Promise?

That means they may not have all of the features of promises (for instance, catch and finally methods). Actual Promise instances would be "fully-fledged" promises.


3 Answers

From the documentation:

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. However, unlike promises, calling a query's .then() can execute the query multiple times.

So unlike an actual promise, if you call then() multiple times on the query, you actually execute the query (or update) multiple times.

If you want an actual promise, call exec() on the query.

let promise = Test.findOne({}).exec();
like image 161
JohnnyHK Avatar answered Oct 01 '22 11:10

JohnnyHK


All promises are thenables, but not all thenables are promises. To make things more complicated, not all promises are Promises (instances created by JavaScript's built-in Promise constructor).

JavaScript promises are an implementation of the Promises/A+ specification, which defines the terms like this:

1.1 “promise” is an object or function with a then method whose behavior conforms to this specification.

1.2 “thenable” is an object or function that defines a then method.

So Mongoose's queries are not promises, not even by that definition, since their then method is not compatible with the Promises/A+ spec. See JohnnyHK's answer for why they aren't compatible with the Promises/A+ spec (they run the query).

In other words, they act like promises but are not JS promises?

They only act a bit like promises. They are not promises. Their then is not implemented per the spec, it has side effects (running the query). If you want a true promise, see JohnnyHK's answer (e.g., use exec).


In general, if you have a thenable that's at least somewhat promise-like, you can get a proper promise for it by using Promise.resolve:

Promise.resolve(theThenable)
.then(/*...*/)
.catch(/*...*/)
.finally(/*...*/);

Promise.resolve will provide a true Promise instance that is resolved to the Mongoose thenable/promise: It will wait for that thenable/promise to settle and then settle the same way. That would work on a Mongoose query (provided you only do it once; exec is the better way with Mongoose queries).

like image 36
T.J. Crowder Avatar answered Oct 01 '22 12:10

T.J. Crowder


They are "promise like", which means you can await them and call .then() and .catch() on them, however they are not instanceof Promise.

like image 27
Jonas Wilms Avatar answered Oct 01 '22 11:10

Jonas Wilms