【发布时间】:2015-10-11 13:04:39
【问题描述】:
我遇到了一段 Mongoose 代码,其中包含一个查询 findOne 和一个 exec() 函数。
我以前从未在 Javascript 中见过这种方法吗?它的具体作用是什么?
【问题讨论】:
标签: javascript mongoose
我遇到了一段 Mongoose 代码,其中包含一个查询 findOne 和一个 exec() 函数。
我以前从未在 Javascript 中见过这种方法吗?它的具体作用是什么?
【问题讨论】:
标签: javascript mongoose
基本上在使用 mongoose 时,可以使用帮助程序检索文档。每个接受查询条件的模型方法都可以通过callback 或exec 方法执行。
callback:
User.findOne({ name: 'daniel' }, function (err, user) {
//
});
exec:
User
.findOne({ name: 'daniel' })
.exec(function (err, user) {
//
});
因此,当您不传递回调时,您可以构建查询并最终执行它。
您可以在mongoose docs 中找到更多信息。
更新
将Promises 与 Mongoose 异步操作结合使用时需要注意的是,Mongoose 查询不是 Promise。查询确实返回一个thenable,但如果你需要一个real Promise,你应该使用exec 方法。更多信息可以在here找到。
在更新期间,我注意到我没有明确回答问题:
我以前从未在 Javascript 中见过这种方法吗?它有什么作用 到底是什么?
嗯,它不是原生 JavaScript 方法,而是 Mongoose API 的一部分。
【讨论】:
exec 方法。这至少是他们在文档中所做的。确保您可以通过Model.find() instanceof require('bluebird') 检查自己。希望这会有所帮助。
Model.update().exec() 以确保它会执行。然后就可以响应api了,不用等待更新。
Daniel 非常漂亮地回答了这个问题。要详细说明构建和执行查询的详尽方法列表,请查看以下用例:
查询构建
在调用 then 或 exec 之前,Mongoose 不会执行查询。这在构建复杂查询时非常有用。一些示例包括使用 populate 和 aggregate 函数。
User.find({name: 'John'}) // Will not execute
通过回调执行
尽管由于其嵌套性质而被许多人不喜欢,但可以通过提供可选的回调来执行查询。
User.find({name: 'John'}, (err, res) => {}) // Will execute
然后 API 作为 Promises/A+
Mongoose 查询确实提供了then 函数。这不应与常规承诺相混淆。简而言之,Promises/A+ 规范需要 then 函数才能像我们习惯的 Promises 一样工作。
User.find({name: 'John'}).then(); // Will execute
Promise.all([User.find({name: 'John'}), User.find({name: 'Bob'})]) // Will execute all queries in parallel
执行函数
来自猫鼬文档If you need a fully-fledged promise, use the .exec() function.
User.find({name: 'John'}).exec(); // Will execute returning a promise
【讨论】:
then 来返回承诺。这与exec 没有太大区别。我发现这很方便的用例是使用Promise.all 之类的东西。不确定exec 返回的承诺是否在这种情况下有效。
我从不使用 exec() 函数在模型上完成 CRUD(创建、读取、更新、删除)。当我想在模型上使用 CRUD 时,我会这样使用它:
const user = await UserModel.findOne(userCondition);
而且它总是能胜任工作。所以我想知道“exec() 是做什么用的”?
当我在猫鼬文档中搜索时,我找到了答案here。
您应该将 exec() 与 await 一起使用吗?
这就是故事。
您有两种方法可以对模型执行查询。使用callback 或使用exec() 函数。 “但是”你也可以使用await。 exec() 函数返回一个承诺,您可以将它与 then() 或 async/await 一起使用以对模型“异步”执行查询。所以问题是“如果我可以使用user = await UserModel.find() 并且它可以正常工作,那么我为什么要使用exec() 函数?”。您可以在document 中找到答案:
使用 await 和 exec() 或不使用 await 有两个区别。
await 与exec() 或不使用它没有区别。就在您调用没有exec() 或callback 的查询时,它会返回一个thenable,它类似于promise 但它不是promise。(您可以找到here 的区别)。但是,当您使用 exec() 运行查询时,您会得到一个承诺作为响应。// 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 和exec(),如果您在执行查询时发现任何错误,您将获得更好的“堆栈跟踪”。所以: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();
【讨论】:
exec() 如果没有提供回调,将返回一个承诺。所以下面的模式非常方便和通用——它可以很好地处理回调或承诺:
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);
}
我建议将 Bluebird Promise 与 Mongoose 一起使用,为此,请使用以下调用:
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
【讨论】:
所有答案都是正确的,但最简单的方法是使用现代异步等待方法..
async ()=> {
const requiresUser = await User.findByIdAndUpdate(userId,{name:'noname'},{ new:true}).exec()
【讨论】: