带有 Mongoose 的 NodeJs - 嵌套查询异步问题
NodeJs with Mongoose - Nested queries async issue
我必须mongodbcollections,像这样:
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 的内部循环结束?
提前致谢,
大卫.
这是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)
})
})
添加对猫鼬承诺的支持。我使用 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++;
});
});
您可以 运行 使用 $lookup
的聚合管道对同一数据库中的另一个集合进行 "left-join" 过滤"joined" 集合中的文档进行处理。有了这个你就不需要任何异步库了:
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"]
}
]
我必须mongodbcollections,像这样:
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 的内部循环结束?
提前致谢,
大卫.
这是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)
})
})
添加对猫鼬承诺的支持。我使用 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++;
});
});
您可以 运行 使用 $lookup
的聚合管道对同一数据库中的另一个集合进行 "left-join" 过滤"joined" 集合中的文档进行处理。有了这个你就不需要任何异步库了:
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"]
}
]