Mongoose - What Does the Exec Function Do

Mongoose - What does the exec function do?

Basically when using mongoose, documents can be retrieved using helpers. Every model method that accepts query conditions can be executed by means of a callback or the exec method.

callback:

User.findOne({ name: 'daniel' }, function (err, user) {
//
});

exec:

User
.findOne({ name: 'daniel' })
.exec(function (err, user) {
//
});

Therefore when you don't pass a callback you can build a query and eventually execute it.

You can find additional info in the mongoose docs.

UPDATE

Something to note when using Promises in combination with Mongoose async operations is that Mongoose queries are not Promises. Queries do return a thenable, but if you need a real Promise you should use the exec method. More information can be found here.

During the update I noticed I didn't explicitly answer the question:

Ive never seen that method in Javascript before? What does it do
exactly?

Well it's not a native JavaScript method, but part of the Mongoose API.

In Mongoose Model.find() and Model.find().exec() produce the same result. So why bother using Model.find().exec()?

Mongoose have explained the difference of both in promises,

There are two alternatives for using await with queries:

  • await Band.find();
  • await Band.find().exec();

As far as functionality is concerned, these two are equivalent. However, we recommend using .exec() because that gives you better stack traces.

With the example:

const doc = await Band.find({ name: "Guns N' Roses" }); // works

const badId = 'this is not a valid id';
try {
await Band.find({ _id: badId });
} catch (err) {
// Without `exec()`, the stack trace does **not** include the
// calling code. Below is the stack trace:
//
// CastError: Cast to ObjectId failed for value "this is not a valid id" at path "_id" for model "band-promises"
// at new CastError (/app/node_modules/mongoose/lib/error/cast.js:29:11)
// at model.Query.exec (/app/node_modules/mongoose/lib/query.js:4331:21)
// at model.Query.Query.then (/app/node_modules/mongoose/lib/query.js:4423:15)
// at process._tickCallback (internal/process/next_tick.js:68:7)
err.stack;
}

try {
await Band.find({ _id: badId }).exec();
} catch (err) {
// With `exec()`, the stack trace includes where in your code you
// called `exec()`. Below is the stack trace:
//
// CastError: Cast to ObjectId failed for value "this is not a valid id" at path "_id" for model "band-promises"
// at new CastError (/app/node_modules/mongoose/lib/error/cast.js:29:11)
// at model.Query.exec (/app/node_modules/mongoose/lib/query.js:4331:21)
// at Context.<anonymous> (/app/test/index.test.js:138:42)
// at process._tickCallback (internal/process/next_tick.js:68:7)
err.stack;
}

Other as well: Queries are not promises:

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function.

const query = Band.find({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));

// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (docs) {
// use docs
});

// `.exec()` gives you a fully-fledged promise
const promise = query.exec();
assert.ok(promise instanceof Promise);

promise.then(function (docs) {
// use docs
});

Mongoose execution with exec() or not?

In the majority of use cases both options will work in similar way.

For some reason, mongoose uses its own promise-like implementation but not the real promises. It means that queries are actually thenable and also can be used with async/await but those are not instances of a real Promise.

When you call .exec() it forces mongoose to return a real, fully fledged Promise object.

The main difference between these two approaches is that an exec one can provide you more details and context information if error occurs - and that is the main reason why using exec is recommended.

There is a separate article related to this topic in the mongoose docs.

mongoose: what is the purpose of Query#exec

query.exec(function(err, result)) has been present forever in mongoose. It allows to pass a callback AND in newer versions of mongoose also returns a promise. Lots of code (old and new) still uses callbacks, so this is probably still more often used than the .then().

the then() method was introduced much later, when mongoose was promisified - but old code should not be broken so exec() will stay forever I guess.

Mongoose find vs exec. How to return values?

You can not mix promise with callbacks in mongoose:

exports.getPopulatedUsers = async function(query){
var docs = await users.find(query).exec();
return docs;
}

as for what's the difference between exec and find, read the links in the comment section they are very clear.

Nodejs - Normal callback vs exec

Just refer the following answer Mongoose - What does the exec function do?

exec normally used for executing dynamically created queries.

The following is a simple code that gives an idea where you can use exec.

employee.find({}, function (err, docs) {
// statements
});

employee.find({}).populate("designation").exec(function (err, docs) {
// statements
});


Related Topics



Leave a reply



Submit