我有两个循环,用户外部循环,内部循环遍历每个用户的venueID。在内部循环中,我想查找场地并将其附加到外部外观(userItem
)中定义的数组中。但是因为forEach是同步的并且mongo数据库查找是异步的,所以结果始终为空。我试图整合this answer,但无济于事。怎么做?
ret = [];
users.forEach(function(user) {
var userItem = user.getSanitised('ADM');
userItem.venues = [];
var tmp = [];
userItem.adminVenueIds.forEach(function(adminVenueId){
tmp.push(function(callback) {
Venue.findOne({_id:adminVenueId}, function(error, venue) {
callback(null, venue.toObject());
});
});
});
async.parallel(userItem.venues, function(err, result) {
/* this code will run after all calls finished the job or
when any of the calls passes an error */
if (err)
return console.log(err);
userItem.venues.push(result);
});
ret.push(userItem);
});
尝试了以下内容,但也不起作用
users.forEach(function(user) {
var userItem = [];
async.series({
setUserItem : function(callback)
{
userItem = user.getSanitised('ADM');
callback(null, 'OK');
},
setUserVenues : function(callback)
{
userItem.venues = [];
user.adminVenueIds.forEach(function(adminVenueId,index) {
Venue.findOne({_id:adminVenueId}, function(error, venue) {
userItem.venues.push(venue.toObject());
if((index+1) == user.adminVenueIds.length)
callback(null, 'OK');
});
});
}
},
function(error, results) {
if(error)
winston.error(error);
ret.push(userItem);
}
);
});
答案 0 :(得分:1)
你可以简单地放一个if语句(在你的情况下把条件作为数组长度)然后当循环完成后你可以通过调用一个函数来继续做它的事情(或者把你的代码放在那里) ,但它会开始变得凌乱)
var ret = [];
var test = [];
for (var i = 0; i < 20; i++) {
for (var x = 0; x < 20; x++) {
setTimeout(function() {
test.push("Test"+x);
if (x === 20) {
finishIt();
}
}, 300)
}
}
function finishIt() {
console.log(test);
ret.push(test);
}
答案 1 :(得分:0)
我想你可能想看看使用Mongoose。它是MongoDB之上的NodeJS应用程序层,提供更多类似SQL的体验。
答案 2 :(得分:0)
我最终得到了以下解决方案。它很脏,但我想这只是nodejs是nodejs。
users.forEach(function(user) {
var userItem = user.getSanitised('ADM');
userItem.venues = [];
user.adminVenueIds.forEach(function(adminVenueId) {
Venue.findOne({_id:adminVenueId}, function(error, venue) {
userItem.venues.push(venue.toObject());
});
});
(function(){
if(userItem.venues.length == user.adminVenueIds.length) {
ret.push(userItem);
} else {
setTimeout(arguments.callee, 30);
}
})();
});