乐闻世界logo
搜索文章和话题

Mongoose 中 Exec 函数的作用是什么?

9 个月前提问
5 个月前修改
浏览次数47

6个答案

1
2
3
4
5
6

exec 函数在 Mongoose 中用于执行一个查询并返回一个 promise。当你使用 Mongoose 构建查询时,直到你调用 execthencatch,或者使用 await 时,查询才会被发送到 MongoDB 数据库执行。

在 Mongoose 中,查询构建器允许链式调用各种方法来构建一个复杂的查询。例如,你可能会使用 findsortlimitselect 等方法。调用 exec 是在链式构建完成之后触发实际数据库操作的一种方式。

这里有一个例子:

javascript
const mongoose = require('mongoose'); const { Schema } = mongoose; // 假设我们有一个名为 User 的模型 const UserSchema = new Schema({ name: String, age: Number, email: String }); const User = mongoose.model('User', UserSchema); // 构建一个查询来查找所有年龄在30岁以上的用户,并按照名称进行排序 User.find({ age: { $gt: 30 } }) .sort('name') .select('name email') .exec() // 在这里,exec() 会执行上面构建的查询 .then(users => { // 处理查询结果 console.log(users); }) .catch(err => { // 处理可能发生的错误 console.error(err); });

在这个例子中,exec 返回一个 promise,该 promise 在查询成功执行后解析查询结果,在出现错误时拒绝。

使用 exec 的优势是可以让你更灵活地处理结果和错误,例如可以使用 async/await 语法,这样代码更加简洁和现代:

javascript
async function findUsers() { try { const users = await User.find({ age: { $gt: 30 } }) .sort('name') .select('name email') .exec(); // 使用 async/await 等待查询结果 console.log(users); } catch (err) { console.error(err); } } findUsers();

在这个例子中,我们通过 await 关键字等待 exec() 的结果,这样就可以用同步代码的方式写异步操作,提高代码的可读性和维护性。

2024年6月29日 12:07 回复

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:

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

exec:

shell
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.

2024年6月29日 12:07 回复

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:

shell
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 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();

  • Another difference is, if you use await with exec() 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();

2024年6月29日 12:07 回复

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.

shell
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.

shell
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.

shell
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.

shell
User.find({name: 'John'}).exec(); // Will execute returning a promise
2024年6月29日 12:07 回复

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:

shell
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:

shell
const mongoose = require('mongoose'); mongoose.Promise = require('bluebird');
2024年6月29日 12:07 回复

all answers are correct but the easiest way is to use modern async await approach..

shell
async ()=> { const requiresUser = await User.findByIdAndUpdate(userId,{name:'noname'},{ new:true}).exec()
2024年6月29日 12:07 回复

你的答案