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?
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?
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.
exec
method. This is what they do in the docs at least. To be sure you can check yourself with Model.find() instanceof require('bluebird')
. Hope this helps. –
Koto Model.update().exec()
to make sure it will execute. Then you can respond to the api without waiting for update. –
Frond const query = await Model.find({});
and then later query.exec();
? –
Cyclostome 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.
await
with exec()
or without it. Just when you call a query without exec()
or callback
, it returns a thenable
which is something like promise but it's not a promise.(You can find the difference here). But when you use exec()
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();
await
with exec()
you get a better "stack trace" if you catch any error in executing queries. So: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();
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
then
on a query to return a promise too. This isn't much different than exec
. The use case I find this handy is when using something like Promise.all
. Not sure if the promise returned by exec
works in such contexts though. –
Larianna Promise.all
example is probably too simplistic, as you should use find(name: { $in: ['John', 'Bob'] })
instead –
Coma 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');
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()
Basically, mongoose queries do not return any promise. So that if we want them to queries work like a promise we use the exec function.
One way to get data:
find().exec((err,data)=>{
})
Other way:
const res=await find()
2023 update
Query.prototype.exec() no longer accepts a callback
Use following pattern:
const result = await Model.findOne({filter:filter}).exec();
return result ;
**or**
const x = await Model.findOne({filter:filter}).exec()
.then((data)=>{
return (data);
}).catch((err)=> {
return (err);
});
© 2022 - 2024 — McMap. All rights reserved.