延迟响应,直到所有查询完成

我的数据库包含项目和阶段。 项目可以有多个阶段。 模型类似于这些:

相:

var phaseSchema = new mongoose.Schema({ project: { type: mongoose.Schema.Types.ObjectId, ref: 'Project' } }); 

项目:

 var projectSchema = new mongoose.Schema({ name : { type: String } }); 

目前我正在使用以下方法来检索每个项目的阶段:

 var calls = []; var projects = _.each(projects, function (p) { calls.push(function (callback) { req.app.db.models.Phase.find({ project: p._id }, function (err, doc) { if (err) { callback(err); } else { p.phases = doc; callback(); } }); }) }); async.parallel(calls, function (err) { workflow.outcome.projects = projects; return workflow.emit('response'); }); 

正如你所看到的,我没有传递任何东西callback()只是(AB)使用asynchronous的 parallel等待响应,直到查找完成。

或者,我可以将阶段对象传递给callback函数,但是parallel我应该遍历阶段和项目以find适合当前阶段的项目。

我是否陷入了这个devise中的一个常见陷阱,出于某种原因,最好迭代一遍项目和阶段,或者我应该采取一种完全不同的方法?

实际上,我认为在这种情况下,您最好运行一个查询来匹配所有潜在的结果。 对于“testing”查询,您可以将所有_id值作为$in子句进行发布,然后仅对结果与源数组进行匹配,以分配匹配(ed)文档:

全部匹配

 // Make a hash from the source for ease of matching var pHash = {}; _.each(projects,function(p) { pHash[p._id.toString()] = p; }); // Run the find with $in req.app.db.models.Phase.find({ "project": { "$in": _.keys(pHash) } },function(err,response) { _.each(response,function(r) { // Assign phases array if not already there if (!phash[r.project.toString()].hasOwnProperty("phases") pHash[r.project.toString()].phases = []; // Append to array of phases pHash[r.project.toString()].phases.push(r) }); // Now return the altered hash as orginal array projects = _.mapObject(pHash,function(val,key) { return val; }); }); 

还像你说的“项目可以有多个阶段” ,所以逻辑将是一个“数组”,而不是一个单一的值的分配。


更有效的$查找

另一方面,如果你有MongoDB 3.2可用,那么$lookup聚合pipe道运营商似乎是为你。 在这种情况下,您只需要使用Projects模型,但在“”阶段“ 集合上进行$lookup 。 由于“收集”是这里的一个术语,因为它是服务器端操作,因此只知道集合而不知道应用程序的“模型”:

 // BTW all models are permanently registered with mongoose mongoose.model("Project").aggregate( [ // Whatever your match conditions were for getting the project list { "$match": { .. } }, // This actually does the "join" (but really a "lookup") { "$lookup": { "from": "phases", "localField": "_id", "foreignField": "project", "as": "phases" }} ],function(err,projects) { // Now all projects have an array containing any matched phase // or an empty array. Just like a "left join" }) ); 

这将是处理这个最有效的方法,因为所有的工作都是在服务器上完成的。

所以你似乎在这里要求的基本上是.populate()的“反例”,而不是在“project”对象上保存“phases”作为引用,而是在“phase”中列出对项目的引用。

在这种情况下,任何forms的“查找”应该是你正在寻找的。 无论是通过$in和“mapping”阶段模拟连接,还是直接使用聚合框架$lookup操作符。

无论哪种方式,这将服务器联系减less到“一个”的操作,因为你目前的方法将创build大量的连接,每个连接和相当数量的资源。 也不需要“等待所有响应” 。 我敢打赌,两者都快得多。