具有Mongoose的NodeJ - 嵌套查询异步问题

时间:2017-04-10 14:32:15

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

我必须使用mongodb集合,如下所示:

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

我想生成一个这样的报告:

ADMINISTRATORS
--------------------------
jlopez
rdiaz

OPERATORS
--------------------------
amiralles
dcamponits

但我收到以下报告:

ADMINISTRATORS
--------------------------
OPERATORS
--------------------------
jlopez
rdiaz
amiralles
dcamponits

以下是生成报告的代码:

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的内部循环结束?

提前致谢,

大卫。

3 个答案:

答案 0 :(得分:0)

这是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)
})
})

答案 1 :(得分:0)

为mongoose添加对promises的支持。我使用q,但你也可以使用蓝鸟。

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++;
    });
});

答案 2 :(得分:0)

您可以运行使用 $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"]
    }
]