Mongoose - What does the exec function do?
JavascriptMongooseJavascript Problem Overview
I came across a piece of Mongoose code that included a query findOne and then an exec() function.
Ive never seen that method in Javascript before? What does it do exactly?
Javascript Solutions
Solution 1 - Javascript
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][1].
[1]:http://mongoosejs.com/docs/queries.html "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.
Solution 2 - Javascript
Daniel has answered this quite beautifully. To elaborate on an exhaustive list of ways to build and execute queries, look at the following use cases:
Query Building
Mongoose will not execute a query until then
or exec
has been called upon it. This is very useful when building complex queries. Some examples can include using the populate
and aggregate
functions.
User.find({name: 'John'}) // Will not execute
Execution via callback
Although disliked by many due to its nesting nature, queries can be executed by providing the optional callback.
User.find({name: 'John'}, (err, res) => {}) // Will execute
Then API as a Promises/A+
Mongoose queries do provide a then
function. This is not to be confused with regular promises. Simply put, the Promises/A+ specification requires a then
function to work much like how we're used to with promises.
User.find({name: 'John'}).then(); // Will execute
Promise.all([User.find({name: 'John'}), User.find({name: 'Bob'})]) // Will execute all queries in parallel
The exec function
From Mongoose docs If you need a fully-fledged promise, use the .exec() function.
User.find({name: 'John'}).exec(); // Will execute returning a promise
Solution 3 - Javascript
I never use exec()
function to complete a CRUD(Create, Read, Update, Delete) on a model. When I want CRUD on a model, I use it like this:
const user = await UserModel.findOne(userCondition);
And it always does the job. So I wondered "what does exec()
use for"?
As I searched in mongoose document, I found the answer here.
> Should You Use exec() With await?
And here is the story.
You have two ways to execute a query on a model. Using callback
or using exec()
function. "But" you can use await
too. exec()
function returns a promise, that you can use it with then()
or async/await
to execute a query on a model "asynchronous". So the question is "If I can just use user = await UserModel.find()
and it works currectly, so why should I use exec()
function?". The answer that you can find in the document is:
There are two difference between using await
with exec()
or without it.
- As a functionality point of view, there is no difference between using
await
withexec()
or without it. Just when you call a query withoutexec()
orcallback
, it returns athenable
which is something like promise but it's not a promise.(You can find the difference here). But when you useexec()
to run a query, you get exactly a promise as response.
// returns a thenable as response that is not a promise, but you can use await and then() with it.
const user = await UserModel.findOne(userCondition);
// returns exactly a promise.
const user = await UserModel.findOne(userCondition).exec();
- Another difference is, if you use
await
withexec()
you get a better "stack trace" if you catch any error in executing queries. So:
These two line, do the same thing:
const user = await UserModel.findOne(userCondition);
// does exactly as the before line does, but you get a better stack trace if any error happened
const user = await UserModel.findOne(userCondition).exec();
Solution 4 - Javascript
exec()
will return a promise if no callback is provided. So the following pattern is very convenient and generic - it can handle callbacks or promises nicely:
function findAll(query, populate, cb) {
let q = Response.find(query);
if (populate && populate.length > 0) {
q = q.populate(populate);
}
// cb is optional, will return promise if cb == null
return q.lean().exec(cb);
}
I recommend using Bluebird promises with Mongoose, to do that, use this call:
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
Solution 5 - Javascript
all answers are correct but the easiest way is to use modern async await approach..
async ()=> {
const requiresUser = await User.findByIdAndUpdate(userId,{name:'noname'},{ new:true}).exec()
Solution 6 - Javascript
one way to get data,
find().exec((err,data)=>{
})
other way,
const res=await find()