Node.js 节点中带有异步mongodb查询的嵌套循环 问题

Node.js 节点中带有异步mongodb查询的嵌套循环 问题,node.js,mongodb,mongodb-query,aggregation-framework,Node.js,Mongodb,Mongodb Query,Aggregation Framework,我在MongoDB有3个系列 地区 每个文档对应一个地理区域,有一个区域名称字段,另一个字段是更广泛区域内的农场数组 细节 此集合包含与特定农场相关的文档,以及与该农场详细信息相关的各种字段,例如奶牛数量 屈服 此集合再次包含文档,其中每个文档都与特定场相关,此实例中的字段用于每天的场输出 我正在尝试编写一个函数,它将从regions集合开始,对于第一个区域,它将获取每个农场ID,并使用它查询其他两个集合,获取该农场的总产量和奶牛总数,然后对每个农场求和,以获得该区域的总数 企图

我在MongoDB有3个系列

  • 地区
    • 每个文档对应一个地理区域,有一个区域名称字段,另一个字段是更广泛区域内的农场数组
  • 细节
    • 此集合包含与特定农场相关的文档,以及与该农场详细信息相关的各种字段,例如奶牛数量
  • 屈服
    • 此集合再次包含文档,其中每个文档都与特定场相关,此实例中的字段用于每天的场输出
我正在尝试编写一个函数,它将从regions集合开始,对于第一个区域,它将获取每个农场ID,并使用它查询其他两个集合,获取该农场的总产量和奶牛总数,然后对每个农场求和,以获得该区域的总数

企图 我第一次尝试对单个区域使用直接的mongodb调用

var db=client.connect('mongodb://localhost:27017/mydb,函数(err,db){
如果(错误)抛出错误;
var regions=db.collection('regions');
var details=db.collection('details');
var收益率=数据库集合(“收益率”);
regions.find({“region”:“Gotham”}).toArray(函数(err,docs){
对于(var k=0;k

在外循环完成后,我想对最终的
regionield
值做点什么,但由于异步mongo调用,按照现在的结构,外循环在内循环中完成必要的计算之前就完成了。我就是想不出如何绕过这个问题。我已经看了很多问题/答案e解释回调,但我不知道如何将其应用到我的案例中。

您可以使用库来简化嵌套异步调用的处理。

我认为您在设计中采用了错误的方法,但稍后会详细介绍。首先,基本上更改您的列表

简单且无额外依赖关系的方法是使用驱动程序直接支持的节点。这允许您依次处理每个文档,也不会像
.toArray()
那样将所有内容加载到内存中

此外,作为“流”,还有一个触发的“结束”事件,以及可以包装发出的查询的自然流控制:

var mongodb=require('mongodb'),
MongoClient=mongodb.MongoClient;
MongoClient.connect('mongodb://localhost/mydb,函数(err,db){
如果(错误)抛出错误;
var regions=db.collection('regions'),
收益率=db.集合(“收益率”);
var resultHash={};
var rstream=regions.find({“region”:“Gotham”});
rstream.on('err',函数(err){
犯错误;
});
rstream.on('end',function()){
console.log('Complete');
log(JSON.stringify(resultHash,未定义,2));
db.close();
});
rstream.on('data',函数(区域){
rstream.pause();//暂停外部流
resultHash[region.region]=0;
var fstream=yield.find({“Farm_ID”:{“$in”:region.farms}});
fstream.on('err',函数(err){
犯错误;
});
fstream.on('end',function(){
console.log(“完成的农场”);
resume();i//恢复外部流
});
fstream.on('data',函数(场){
fstream.pause();//暂停内部流
结果ash[地区.地区]+=农场产量;
fstream.resume();//恢复内部流
});
});
});
这基本上是对另一个文档中匹配的“区域”的所有“产量”值进行“求和”。还要注意的是,非常简单的使用传递数组中已经存在的所有“农场”,而不是处理另一个循环

但无论如何,你真的不应该这样做。数据库是“智能”的,你的设计需要更智能

您可以通过基本上将“区域”数据添加到“产量”数据中来避免这里的所有麻烦。然后,这只是一个运行问题:

因此,对于“收益率”中的数据:

{“地区”:“高谭”,“产量”:123}
然后只运行以下代码:

yield.aggregate(
[
{“$组”:{
“_id”:“$region”,
“收益率”:{“$sum”:“$yield”}
}}
],
功能(错误、结果){
}
);
这一切都完成了,代码中没有循环或计算

因此,如果您只需将“相关数据”如“区域”添加到您想要处理的“产量”数据中,那么MongoDB已经有了一些工具,可以轻松地在该键上进行累积


这就是脱离关系设计的意义所在。事物的工作方式不同,因此您需要以不同的方式处理它们。而且更智能。

您还可以在循环中使用let而不是var

var db = client.connect('mongodb://localhost:27017/mydb', function(err,db) {
  if (err) throw err;

  var regions = db.collection('Regions');
  var details = db.collection('Details');
  var yield = db.collection('Yield');

regions.find({"region" : "Gotham"}).toArray(function(err, docs) {

  for (let k = 0; k < docs.length; k++) {
    var regionYield = 0;

    for (let j = 0; j < docs[k].farms.length; j++) {
      var farmYield = 0;
      var farmID = docs[k].farms[j]
      yield.find({Farm_ID: farmID}).toArray(function(err, docs) {

        for (let i = 0; i < docs.length; i++) {
          farmYield += +docs[i].Yield;
        }
        console.log('finished inner loop');

        regionYield += farmYield;
      });
    }
    console.log('finished middle loop');
  }
  console.log('finished outer loop');
});
var db=client.connect('mongodb://localhost:27017/mydb,函数(err,db){
如果(错误)抛出错误;
var regions=db.collection('regions');
var details=db.collection('details');
var收益率=数据库集合(“收益率”);
regions.find({“region”:“Gotham”}).toArray(函数(err,docs){
for(设k=0;k