【问题标题】:Mongoose - What does the exec function do?Mongoose - exec 函数有什么作用?
【发布时间】:2015-10-11 13:04:39
【问题描述】:

我遇到了一段 Mongoose 代码,其中包含一个查询 findOne 和一个 exec() 函数。

我以前从未在 Javascript 中见过这种方法吗?它的具体作用是什么?

【问题讨论】:

    标签: javascript mongoose


    【解决方案1】:

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

    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 的一部分。

    【讨论】:

    • 如果我设置了 mongoose.Promise = require('bluebird'),我还需要使用 .exec() 吗?谢谢。
    • @wayofthefuture 我发现文档对这个问题真的很困惑,但我相信你仍然需要调用exec 方法。这至少是他们在文档中所做的。确保您可以通过Model.find() instanceof require('bluebird') 检查自己。希望这会有所帮助。
    • 然后还有其他操作的问题,例如 delete 和 insertMany... 在这些情况下是否需要 exec() ?删除必须在后台使用某种查询...
    • exec 也返回了一个promise,如果没有通过回调,不得不说非常方便
    • 它可能会救人。如果您认为 Model.update() 会完成它的工作并且不要等待一些不那么重要的数据被更新并返回对 API 的响应;您的更新不会执行。您需要Model.update().exec() 以确保它会执行。然后就可以响应api了,不用等待更新。
    【解决方案2】:

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

    查询构建

    在调用 thenexec 之前,Mongoose 不会执行查询。这在构建复杂查询时非常有用。一些示例包括使用 populateaggregate 函数。

    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
    

    【讨论】:

    • 文档没有明确提到它,但示例显示 User.save() 也返回了一个承诺。除了 exec() 和 save() 模型上的任何其他猫鼬方法是否返回一个承诺,或者只是这两个?
    • 如上所述,您也可以在查询中使用then 来返回承诺。这与exec 没有太大区别。我发现这很方便的用例是使用Promise.all 之类的东西。不确定exec 返回的承诺是否在这种情况下有效。
    • 你能用 .exec() 添加一个完整的例子吗? @AnshulKoka 是 .exec() 自动使查询异步还是我应该添加 async/await
    • 使查询异步需要 async/await 所以我不确定我是否理解这个问题。只需在我的示例前面加上 await 前缀,即可获得完整示例。
    【解决方案3】:

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

    const user = await UserModel.findOne(userCondition);
    

    而且它总是能胜任工作。所以我想知道“exec() 是做什么用的”? 当我在猫鼬文档中搜索时,我找到了答案here

    您应该将 exec() 与 await 一起使用吗?

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

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

    • 从功能的角度来看,使用awaitexec() 或不使用它没有区别。就在您调用没有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(); 
    
    • 另一个区别是,如果您使用awaitexec(),如果您在执行查询时发现任何错误,您将获得更好的“堆栈跟踪”。所以:

      这两行,做同样的事情:
    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(); 
    

    【讨论】:

    • 非常重要的区别!在测试我的查询时,我注意到当我故意扭曲 url 中 _id 字段的格式以测试错误时,try/catch 没有选择错误并且我的模型发出了不推荐使用的警告,这承诺返回的错误是未抓到的,以后不会再入住了。
    • 解释清楚,谢谢。
    【解决方案4】:

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

    【讨论】:

    • 为什么我们需要蓝鸟?当我们有 exec()
    【解决方案5】:

    所有答案都是正确的,但最简单的方法是使用现代异步等待方法..

    async ()=> {
    const requiresUser = await User.findByIdAndUpdate(userId,{name:'noname'},{ new:true}).exec()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 2012-01-07
      • 2017-08-26
      • 2012-03-02
      • 1970-01-01
      • 2012-12-11
      • 2012-08-03
      相关资源
      最近更新 更多