如何同步请求?

我正在使用nodejs + express + mongoose。 假设我有两个模式和模式:“水果”和“蔬菜”。

假设我有以下几点:

var testlist = ["Tomato", "Carrot", "Orange"]; var convertedList = []; // Assume res is the "response" object in express 

我希望能够分别检查“水果”和“蔬菜”collections中的每个项目,并将它们插入转换的列表中,其中将番茄,胡萝卜和西兰花replace为它们各自的文档。

下面我有一些我认为会是的伪代码,但是不知道该怎么做。

 for(var i = 0; i < testlist.length; i++) { var fruitfind = Fruit.find({"name":testlist[i]}); var vegfind = Vegetables.find({"name":testlist[i]}); // If fruit only if(fruitfind) { convertedList.push(fruitfindresults); } // If vegetable only else if(vegfind) { convertedList.push(vegfindresults); } // If identified as a fruit and a vegetable (assume tomato is a doc listed under both fruit and vegetable collections) else if (fruitfind && vegfind) { convertedList.push(vegfindresults); } } // Converted List should now contain the appropriate docs found. res.send(convertedList) // Always appears to return empty array... how to deal with waiting for all the callbacks to finish for the fruitfind and vegfinds? 

做这个的最好方式是什么? 或者这甚至有可能?

假设每个水果/蔬菜中只有一个,并且你打算把这两个系列中的素食推两次。

 var async = require("async"), testlist = ["Tomato", "Carrot", "Orange"]; async.map(testlist, function (plant, next) { async.parallel([function (done) { Fruit.findOne({"name": plant}, done); }, function (done) { Vegetables.findOne({"name": plant}, done); }], function (err, plants) { // Edited: before it was (err, fruit, veggie) which is wrong next(err, plants); }); }, function (err, result) { var convertedList = [].concat(result); res.send(convertedList); }); 

注意:实际上没有testing代码,但它应该工作。 asynchronous模块是非常好的pipe理callback这样顺便说一句。

更新

为了获得每个水果只有一次,async.parallelcallback只需要像这样重写:

 function (err, plants) { next(err, plants[0] || plants[1]); } 

在.mapcallback中不需要concat:

 function (err, result) { res.send(result); } 

find是一个asynchronous函数,它向mongo数据库发出一个请求。 这意味着两件事情:

  1. 这些函数不会立即返回结果。 mongoose的findfunction遵循一个非常常见的asynchronous模式。 它接受一个“callback”函数,它将调用结果或错误。 按照节点约定,如果第一个参数不为空,那就是错误。

     // So typically you'd call find like this SomeModel.find({your: 'conditions'}, function (err, results) { if (err) { // some error has occurred which you must handle } else { res.send(results); } }) // note that if code existed on the lines following the find, it would // be executed *before* the find completed. 
  2. 由于每个查询都将另一个请求发送到数据库,因此您通常可以限制该数字。 在这种情况下,不是通过名字查找每个水果/蔬菜,而是通过使用mongo的$in来一次查找所有的名字。

考虑到这两点,你的代码可能看起来像这样:

 // here *first* we're finding fruits Fruit.find({name: {$in: testlist}}, function (err, fruits) { // when the fruit request calls back with results, we find vegetables Vegetable.find({name: {$in: testlist}}, function (err, vegetables) { // finally concat and send the results res.send(fruits.concat(vegetables)); }); }); 

要同时发生这两个请求,需要做更多的工作。 你可以使用像async一样的库,或者自己写一些东西:

 var fruits , vegetables , done = function () { if (fruits && vegetables) { res.send(fruits.concat(vegetables)); } } Fruit.find({name: {$in: testlist}}, function (err, docs) { fruits = docs; done(); }); Vegetable.find({name: {$in: testlist}}, function (err, docs) { vegetables = docs; done(); }); 

请注意,这两个示例在这里简单地连接结果并发送它们,因为不清楚如何处理结果。 这意味着,如果一个西红柿在这两个列表中,它会出现在结果两次,无论是蔬菜和水果的文件。

你还需要处理从mongoose回来的任何错误。

编辑 :唯一命名的文档

根据你的评论,这是一种方法,你可能只返回一个文件的番茄(或其他logging,水果和蔬菜)

 // after retrieving fruits and vegetables, create a map which will // serve to weed out docs with duplicate names var map = {}; fruits.forEach(function (fruit) { map[fruit.name] = fruit; }); vegetables.forEach(function (vegetable) { map[vegetable.name] = vegetable; }); var results = []; // this would sort by name Object.keys(map).sort().forEach(function (key, i) { results[i] = map[key]; }); res.send(results); 

请注意,如果您需要sorting和分页或以其他方式限制两个查询的结果,则此类事情会变得更加复杂,如果您需要这样做,则可以考虑将文档保留在同一个集合中。