通过Array进行迭代,asynchronous更新/创build对象,当一切完成时调用callback

我有一个问题,但我不知道如何去解决这个问题。

我正在使用loopback,但是我想迟早会在mongodb中遇到同样的问题。 让我解释我在做什么:

  • 我从另一个REST服务获取条目,然后为我的API响应准备条目(条目尚未准备好,因为它们没有来自我的数据库的ID)
  • 在我发送响应之前,我想检查数据库中是否存在条目,如果不存在:
    • 创build它,如果它(由source_id确定):
    • 使用它并更新到更新的版本
  • 用条目发送响应(条目现在有分配给它们的数据库ID)

这看起来没问题,而且容易实现,但是并不像我所知道的那样。 我将尝试在代码中进一步解释:

//This will not work since there are many async call, and fixedResults will be empty at the end var fixedResults = []; //results is array of entries results.forEach(function(item) { Entry.findOne({where: {source_id: item.source_id}}, functioN(err, res) { //Did we find it in database? if(res === null) { //Create object, another async call here fixedResults.push(newObj); } else { //Update object, another async call here fixedResults.push(updatedObj); } }); }); callback(null, fixedResults); 

注意:我遗漏了一些代码,但是如果你仔细阅读,我认为它是非常明显的。

所以我想要遍历所有对象,在数据库中创build或更新它们,然后在更新/创build所有对象时使用它们。 我将如何做到这一点?

你可以使用promise。 它们是在其他条件完成后调用的callback函数。 下面是一个链接在一起的承诺https://coderwall.com/p/ijy61g的例子。

q库是一个很好的 – https://github.com/kriskowal/q

这个问题如何使用q.js承诺与多个asynchronous操作一起工作给出了一个很好的代码示例,说明如何构build这些代码。

这种模式通常被称为“asynchronous映射”

var fixedResults = []; var outstanding = 0; //results is array of entries results.forEach(function(item, i) { Entry.findOne({where: {source_id: item.source_id}}, functioN(err, res) { outstanding++; //Did we find it in database? if(res === null) { //Create object, another async call here DoCreateObject(function (err, result) { if (err) callback(err); fixedResults[i] = result; if (--outstanding === 0) callback (null, fixedResults); }); } else { //Update object, another async call here DoOtherCall(function (err, result) { if(err) callback(err); fixedResults[i] = result; if (--outstanding === 0) callback (null, fixedResults); }); } }); }); callback(null, fixedResults);

你可以使用async.map 。 对于数组中的每个元素,运行数组迭代器函数,对每个元素执行你想做的操作,然后用结果(而不是fixedResults.push)运行callback,当全部完成时触发映射callback。 然后每个迭代广告数据库调用将并行运行。

Mongo有一个叫做upsert的函数。

http://docs.mongodb.org/manual/reference/method/db.collection.update/

它完全符合你所要求的而不需要检查。 你可以将所有的三个请求都打开,只是validation结果是否为真。 不需要额外的处理。