nodejs 等到循环中的所有 MongoDB 调用完成

Posted

技术标签:

【中文标题】nodejs 等到循环中的所有 MongoDB 调用完成【英文标题】:nodejs wait until all MongoDB calls in loop finish 【发布时间】:2016-02-13 08:32:48 【问题描述】:

我正在逐行读取 CSV 文件中的数据流,并在每一行上调用 findOne MongoDB,我如何才能等到每一行的所有 mongo 调用完成后再运行下一个函数?

我见过 Promises 可以做到吗?但是我发现 Promises 非常难以理解。而且我发现的所有例子似乎都没有涵盖我正在尝试的内容。 :/

var validProducts = [];

fs.createReadStream(req.file.path)
  .pipe(csvStream)
  .on('error', function (err) 
    console.error(err);
  )
  // loop through all rows
  .on('data', function (data) 
    if (data.size === 'a3') 
      ProductModel.findOne( sku: data.sku , function (err, product) 
        if (product !== null) 
          product.size = data.size;
          product.save();
          validProducts.push(product);
        
      );
    
  );

// on finish make call to other function
socket.emit( 'status': 'complete' );
otherFunction(validProducts);

on('finish')on('end') 只会在数据流的末尾调用,而不是在 Monogo 调用之后。

如果我可以使用承诺,有人可以解释一下吗?

【问题讨论】:

【参考方案1】:

您可以使用Q API 女巫让您做出承诺。有一个有趣的函数可以让你等待一系列 Promise 被解决。以下是如何使用Q.all 解决问题的示例:

var validProducts = [];
var promises = [];

function handleData(data) 
    if (data.size === 'a3') 

        var deferred = Q.defer();

        ProductModel.findOne( sku: data.sku , function (err, product) 
            if (err) 
                deferred.reject(new Error(err));
            

            if (product) 
                product.size = data.size;
                product.save();
                deferred.resolve(product);
                validProducts.push(product);
            

        );

        promises.push(deferred.promise);

    


function handleEnd() 
    Q.all(promises).done(function (values) 
        socket.emit( 'status': 'complete' );
        otherFunction(validProducts);
    );


fs.createReadStream(req.file.path)
  .on('data', handleData)
  .on('end', handleEnd);

【讨论】:

:P 我一个人就这么接近这个了,。但没有正确设置延迟的东西。 这根本不会wait till all the mongo calls from each row are complete before I run the next function 也许我的逻辑有缺陷?如果我错了,请纠正我,但是当没有更多数据可以从文件中读取时,我们正在等待所有的承诺在执行指定的函数之前得到解决。 如果我的想法是正确的,则在将任何内容添加到 promises 数组之前,流将 end。所以Q.all(promises) 会立即执行。 :// 其实一开始有错字!我编辑了它,我认为它会被忽视。很高兴 ;)【参考方案2】:

使用pause/resume

  .on('data', function (data) 
    if (data.size === 'a3') 
      this.pause(); // pause it
      var stream = this; // save 'this'
      ProductModel.findOne( sku: data.sku , function (err, product) 
        if (product !== null) 
          product.size = data.size;
          product.save();
          validProducts.push(product);
        
        stream.resume(); //resume it
      );
    
  );

【讨论】:

这不是使函数同步,而不是异步吗? 关闭。但是.resume().push() 需要在来自.save() 的回调中发生。也不确定this 是否暴露,因此您可能需要先从外部抓取流。 这是一个数据库的 I/O 函数。节点中几乎所有的 I/O 都是异步的,或者应该是异步的。 我实际上认为我不知道问题是什么:D - 我认为 each row 正在由 on('data' 函数处理 I/O 是异步的,但是如果流暂停直到前一个完成,则一次只会发生一个 mongo 调用,这使得它同步(技术上),同时也(技术上)回答我的问题..ish。

以上是关于nodejs 等到循环中的所有 MongoDB 调用完成的主要内容,如果未能解决你的问题,请参考以下文章

按月对记录进行分组并计数 - Mongoose、nodeJs、mongoDb

nodejs操作mongodb查询所有数据

如何循环集合中的所有文档-Azure CosmosDB-Nodejs

从nodejs查询MongoDB中的日期范围

等到 for 循环内的所有函数调用结束其执行 - Javascript

搜索数组 MongoDB NodeJS