【问题标题】:NodeJs with Mongoose - Nested queries async issueNodeJs with Mongoose - 嵌套查询异步问题
【发布时间】:2017-09-05 15:52:58
【问题描述】:

我要mongodb集合,像这样:

UserGroup collection
    fields: 
        name: String
        group_id: Number
User collection
    fields:
        user_name: String
        group_id: Number

我想生成这样的报告:

管理员 -------------------------- 伊洛佩斯 迪亚兹 运营商 -------------------------- 阿米拉莱斯 樟脑

但我得到以下报告:

管理员 -------------------------- 运营商 -------------------------- 伊洛佩斯 迪亚兹 阿米拉莱斯 樟脑

以下是生成报告的代码:

UserGroup.find({}, (err, groups) => {
    for(var i in groups){   
        console.log(groups[i].name)
        console.log("--------------------")
        User.find( {group_id : groups[i].group_id}, (err, users) =>{
            for(var j in users){
                console.log(users[j].user_name)
            }
        })
    }
})

显然,这是 NodeJs/Mongoose 的异步问题。

问题:如何让第一个 For 循环等到每个 UserGrop 的内部循环结束?

提前致谢,

大卫。

【问题讨论】:

    标签: node.js asynchronous mongoose nested nested-queries


    【解决方案1】:

    这是asyc 的一个很好的用例,你可以从下面的代码中得到一个基本的想法。它基于异步每个和瀑布。 [请自行为以下代码添加适当的错误处理。]

    UserGroup.find({}, (err, groups) => {
      async.each(groups, (group, callback) =>{
        async.waterfall([
          (wCallback) => {
            User.find({group_id : group.group_id}, wCallback)
          },
          (users, wCallback) => {
            console.log(group.name)
            console.log("--------------------")
            for(var j in users){
              console.log(users[j].user_name)
            }
            wCallback()
          }
        ], callback)
    })
    })
    

    【讨论】:

    • 我是完美的拉坦库马尔。非常感谢!
    • 嗨拉坦。我是 Stackoverflow 的新手。首先,我很惊讶人们反应如此之快。虽然我说您的回答解决了问题,但我认为用户 chridam 提到的使用Aggregation Pipeline 是最好的解决方案,因为它不需要使用外部库。 无论如何,非常感谢!
    【解决方案2】:

    添加对猫鼬的承诺的支持。我使用 q,但你也可以使用 bluebird。

    mongoose.Promise = require('q').Promise;
    

    然后您可以在所有用户查询完成后使用 q.all 进行解析。

    var promises = []; 
    var groups = [];
    UserGroup.find({}, (err, groups) => {
        for(var i in groups){
            groups.push(groups[i]);
            promises.push(User.find( {group_id : groups[i].group_id}));
        }
    });
    
    q.all(promises).then( function(usersByGroup){
        var indx = 0;
        usersByGroup.forEach(function(users){
    
        var grp = groups[indx];
        console.log(groups[i].name);
        console.log("--------------------");
        for(var j in users){
            console.log(users[j].user_name)
        }
        indx++;
        });
    });
    

    【讨论】:

      【解决方案3】:

      您可以运行一个聚合管道,该管道使用 $lookup 对同一数据库中的另一个集合进行“左连接”,以过滤来自“已连接”集合的文档进行处理。有了这个你就不需要任何异步库了:

      UserGroup.aggregate([
          {
              "$lookup": {
                  "from": "users",
                  "localField": "group_id",
                  "foreignField": "group_id",
                  "as": "users"
              }
          },
          {
              "$project": {
                  "_id": 0,
                  "name": 1,
                  "users": {
                      "$map": {
                          "input": "$users",
                          "as": "user",
                          "in": "$$user.user_name"
                      }
                  }
              }
          }
      ], (err, groups) => {
          if (err) throw err;
          console.log(JSON.stringify(groups, null, 4));
      })
      

      样本输出

      [
          {
              "name": "ADMINISTRATORS",
              "users": ["jlopez", "rdiaz"]
          },
          {
              "name": "OPERATORS",
              "users": ["amiralles", "dcamponits"]
          }
      ]
      

      【讨论】:

      • 这很好用,正如你提到的,没有必要使用另一个库。 ¡ 非常感谢你!
      猜你喜欢
      • 2019-02-08
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 2017-06-19
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      相关资源
      最近更新 更多