2017-04-10 61 views
1

我不得不MongoDB的集合,像這樣:的NodeJS與貓鼬 - 嵌套查詢異步問題

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的內部循環結束?

在此先感謝,

David。

回答

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"] 
    } 
] 
+1

這很有效,正如你提到的那樣,沒有必要使用另一個庫。 ¡非常感謝你chridam! –

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

我是完美的拉坦·庫馬爾。非常感謝你! –

+0

你可以接受這個答案。 ;)歡迎。 –

+2

嗨拉坦。我是新來的Stackoverflow。 首先,我很驚訝人們迴應的速度有多快。 雖然我說你的答案解決了這個問題,但我認爲使用用戶_chridam_提到的'Aggregation Pipeline'是最好的解決方案,因爲它不需要使用外部庫。 **無論如何非常感謝你!** –

0

添加對承諾的支持貓鼬。我使用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++; 
    }); 
});