【问题标题】:What kind of promise does the promisified MongoDB Node driver .forEach() return?承诺的 MongoDB 节点驱动程序 .forEach() 返回什么样的承诺?
【发布时间】:2016-12-05 18:20:08
【问题描述】:

我最近开始在我的 Node.js 项目中使用箭头函数、promise (bluebird) 和 MongoDB。正如你在下面看到的,我承诺了所有的 mongodb 原生驱动。到目前为止,它就像一个魅力。

现在,我想使用 .forEach() 方法,我想知道应该如何使用它。这是想法:

var Promise = require("bluebird");
var mongodb = Promise.promisifyAll(require("mongodb"));
var MongoClient = mongodb.MongoClient;

MongoClient
.connect('the_URL_of_my_database')
.then( (database) => {
  var db = database;
  var myCollection = database.collection('my_collection');

  myCollection
  .find('my_awesome_selector')
  .forEach( (document) => {
    
    var selector = {hashkey: document.hashkey};
    var update = {$set: {data: 'my_new_data'}};
    
    myCollection
    .updateOne(selector, update)
    .then( (response) => {
      // do something if needed
    })
    .catch( (err) => {/*update error handling*/});
    
  })
  .then( (/*do we get some kind of input here ?*/) => {
    // do something once EVERY document has been updated
  })
  .catch( (err) => {/*forEach error handling*/});

})
.catch( (err) => {/*connection error handling*/});

我的问题是:

  1. 承诺的 .forEach() 返回什么?这是一个承诺,一旦所有文件都被更新,就会得到解决?
  2. 如果我的代码不起作用,您知道如何正确实现它吗?

[对我有很大帮助的可选问题:]

  1. 我注意到 MongoDB 驱动程序中的 .each() 方法。它被标记为“已弃用”,但它有什么用处,还是我应该坚持使用 .forEach() ?
  2. 整个 sn-p 对您来说是否有意义,或者我应该注意哪些新手错误/改进?

非常感谢您的任何回答或建议!

[编辑:我确定了更新。我觉得我又回到了回调地狱]

【问题讨论】:

  • 如果你使用promisifyAll,那么.forEach根本不会改变。返回承诺的将是.forEachAsync。但是,集合的 forEach 回调不是 nodeback 而是迭代器,所以你根本不能承诺它。
  • @Bergi :我理解我的错误。但是,我怎样才能实现顺序:(1)选择集合中的一组文档,有或没有光标; (2) 对每个选定的文档执行一个操作; (3) 解决所有先前的操作后做其他事情吗?
  • IIRC,.toArrayAsync 工作,然后让您使用 Bluebird 的承诺感知迭代方法
  • 如何使用promisifyAll?

标签: javascript node.js mongodb promise bluebird


【解决方案1】:

你不需要蓝鸟来做这些。 mongo 驱动程序内置了 Promise。由于forEach 不返回任何内容,您可以使用map() 将每个文档更新处理为一个promise,使用toArray() 将它们缩减为一组promise,然后使用Promise.all() 解析该数组中的每个promise :

var mongodb = require("mongodb");
var MongoClient = mongodb.MongoClient;

MongoClient
  .connect('the_URL_of_my_database')
  .then((db) => {

    var myCollection = db.collection('my_collection');

    myCollection.find({})
      .map((document) => {

        var selector = { _id: document._id };
        var update = { $set: { data: 'my_new_data' } };
        return myCollection
          .updateOne(selector, update)
          .then((response) => {
            // this is each resolved updateOne. You don't need
            // this `.then` unless you want to post-process
            // each individual resolved updateOne result
            console.log(response.result);
            // return each value to accumulate it in Promise.all.then()
            return response.result;
          });
      })
      .toArray() // accumulate the .map returned promises
      .then((promises) => Promise.all(promises)) // iterate through and resolve each updateOne promise
      .then((resolvedPromises) => {
        // an array of all the results returned from each updateOne
        console.log(resolvedPromises);
      })
      .catch((error) => {
        // error handle the entire chain.
      });
  })
  .catch((error) => {
    // error handle the connection
  });

我注意到 MongoDB 驱动程序中的 .each() 方法。它被标记为“已弃用”,但它有什么用处,还是我应该坚持使用 .forEach() ?

我认为 .each() 已被弃用,而支持 .forEach() 是为了与 Array 原型保持一致。

【讨论】:

  • 是的,当我花时间在 mongodb 驱动程序中时,我意识到现在已经内置了 Promise!非常感谢这些解释。我明白了,现在我想我得花一些时间来消化这一切;-)
  • 此方法还要求您将所有数据加载到内存中。需要一种通过游标使用 Promise 的方法。
  • @chovy 如果你担心内存,你最好使用流而不是承诺。
  • 它只会拉出你能处理的量。如果您想提出问题或链接到您提出的问题,我可以在那里回答。
猜你喜欢
  • 2017-07-23
  • 1970-01-01
  • 2020-04-27
  • 2016-06-15
  • 1970-01-01
  • 2015-06-05
  • 2017-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多