猫鼬 - exec函数有什么作用?

use*_*133 80 javascript mongoose

我遇到了一段包含查询findOne然后是exec()函数的Mongoose代码.

我以前从未在Javascript中看过那种方法?它究竟做了什么?

dan*_*ouz 108

基本上,当使用mongoose时,可以使用帮助程序检索文档.接受查询条件的每个模型方法都可以通过a callbackexec方法执行.

callback:

User.findOne({ name: 'daniel' }, function (err, user) {
  //
});
Run Code Online (Sandbox Code Playgroud)

exec:

User
  .findOne({ name: 'daniel' })
  .exec(function (err, user) {
      //
  });
Run Code Online (Sandbox Code Playgroud)

因此,当您不传递回调时,您可以构建查询并最终执行它.

您可以在mongoose文档中找到其他信息.

UPDATE

Promises与Mongoose异步操作结合使用时需要注意的是Mongoose查询不是 Promise.查询并返回一个thenable,但如果你需要一个真正的承诺,你应该使用的exec方法.更多信息可以在这里找到.

在更新期间,我注意到我没有明确回答这个问题:

我以前从未在Javascript中看过那种方法?它究竟做了什么?

好吧,它不是本机JavaScript方法,而是Mongoose API的一部分.

  • 如果我设置了mongoose.Promise = require('bluebird'),我还需要使用.exec()吗?谢谢. (4认同)
  • @wayofthefuture我发现文档真的让人困惑,但我相信你仍然需要调用`exec`方法.这是他们至少在文档中所做的.为了确保你能用`Model.find()instanceof require('bluebird')`来检查自己.希望这可以帮助. (4认同)

Ans*_*oka 36

丹尼尔非常漂亮地回答了这个问题.要详细说明构建和执行查询的详尽方法列表,请查看以下用例:

查询构建

猫鼬将不执行查询,直到then或者exec在它被调用.这在构建复杂查询时非常有用.一些示例可以包括使用populateaggregate函数.

User.find({name: 'John'}) // Will not execute
Run Code Online (Sandbox Code Playgroud)

通过回调执行

虽然由于其嵌套性质而受到许多人的不喜欢,但是可以通过提供可选的回调来执行查询.

User.find({name: 'John'}, (err, res) => {}) // Will execute
Run Code Online (Sandbox Code Playgroud)

然后API作为Promises/A +

Mongoose查询确实提供了一个then功能.这不应与常规承诺相混淆.简而言之,Promises/A +规范要求then函数的工作方式与我们习惯承诺的方式非常相似.

User.find({name: 'John'}).then(); // Will execute
Promise.all([User.find({name: 'John'}), User.find({name: 'Bob'})]) // Will execute all queries in parallel
Run Code Online (Sandbox Code Playgroud)

exec功能

来自Mongoose docs If you need a fully-fledged promise, use the .exec() function.

User.find({name: 'John'}).exec(); // Will execute returning a promise
Run Code Online (Sandbox Code Playgroud)


far*_*rid 7

我从不使用exec()函数在模型上完成 CRUD(创建、读取、更新、删除)。当我想在模型上使用 CRUD 时,我会像这样使用它:

const user = await UserModel.findOne(userCondition);
Run Code Online (Sandbox Code Playgroud)

它总是能胜任。所以我想知道“有什么exec()用”?当我在猫鼬文档中搜索时,我在这里找到了答案。

你应该在等待中使用 exec() 吗?

这是故事。
您有两种方法可以对模型执行查询。使用callback或使用exec()功能。“但是”你也可以用awaitexec()函数返回一个承诺,您可以将它与“异步”模型一起使用then()async/await执行查询。所以问题是“如果我可以使用user = await UserModel.find()并且它可以正常工作,那么我为什么要使用exec()函数?”。您可以在文档中找到的答案是:

使用awaitexec()不使用它有两个区别。

  • 作为视图的官能度点,存在使用之间没有差异awaitexec()或没有它。就在你调用一个没有exec()or的查询时callback,它返回一个thenable类似于 promise 的东西,但它不是一个 promise。(你可以在这里找到区别)。但是当您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(); 
Run Code Online (Sandbox Code Playgroud)
  • 另一个区别是,如果您使用awaitwith ,如果您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(); 
Run Code Online (Sandbox Code Playgroud)

  • “就功能而言,这两者是等效的。但是,我们建议使用 .exec(),因为这可以为您提供更好的堆栈跟踪。” [直接文档参考](https://mongoosejs.com/docs/promises.html#should-you-use-exec-with-await)。 (3认同)

Ale*_*lls 6

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

}
Run Code Online (Sandbox Code Playgroud)

我建议使用Mongoose的Bluebird promises,为此,请使用此调用:

const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
Run Code Online (Sandbox Code Playgroud)

  • 为什么我们需要蓝鸟?当我们有 exec() 时 (3认同)