Scenario: There are users and users has many posts. For a particular group of users, I need to fetch 10 recent posts per user and send them in response.
Here is what I have come up with:
用户是具有用户信息的数组。
var allPosts = [];
for(var i=0; i<users.length; i++){
(function(i){ //Level-1
db.collection('posts', function(err, postCollection){
(function(i){ //Level-2
postCollection.find({"user_id": users[i]['user_id']}).sort({"created": -1}).limit(10).toArray(function(err, post) {
(function(i){ //Level-3
for(var j =0; j< post.length; j++){
(function(j){
post[j]['created'] = ObjectId(post[j]['_id'].toString()).getTimestamp();
allPosts.push(post[j]);
if(j === post.length-1){
res.send(allPosts);
}
})(j);
}
})(i);
});
})(i);
});
})(i);
}
现在,执行顺序保留到Level-2,但是当它进入Level-3时,所有事情都出错:我有两个用户在阵列中,一个用户有3个帖子,另一个有10个帖子,有时回复只有3个帖子,有时候全部是13个帖子。我认为这是因为MongoDB。我甚至通过使用立即调用的函数表达式(IIFE)来处理执行顺序,但它似乎在这里似乎不起作用。 任何帮助表示赞赏。 感谢
答案 0 :(得分:1)
首先,你应该美化你的代码。 在其他循环的回调中使用循环内部的匿名函数并不容易维护或读取。
您的代码的问题在于,在最后一个循环(j循环)中,您在查询其他用户之前得到j == users.length - 1,因此发送的响应将完成后查询的数量,直到那一刻。
您犯的另一个重大错误是您在循环中请求 post 集合。 那是错的!你应该缓存数据库和集合。
试试这段代码:
var allPosts = [];
var post_collection = null;
var get_user = function(i, callback) {
post_collection
.find({"user_id": users[i]['user_id']})
.sort({"created": -1})
.limit(10)
.toArray(function(err, post) {
// Do something when you get error
// Always call the callback function if there is one
if(err) {
callback();
return;
}
for(var j=0; j<post.length; ++j) {
post[j]['created'] = ObjectId(post[j]['_id'].toString()).getTimestamp();
allPosts.push(post[j]);
}
callback();
});
};
var fetch_users = function() {
var count = users.length;
for(var i=0; i<users.length; ++i) {
get_user(i, function() {
// Each time a query for one user is done we decrement the counter
count--;
// When the counter is 0 we know that all queries have been done
if(count === 0) {
res.send(allPosts);
}
});
};
};
// Get the collection, check for errors and then cache it!
db.collection('posts', function(err, postCollection) {
// Always check for database errors
if(err) {
console.log(err);
return;
}
post_collection = postCollection;
fetch_users();
});
您应该知道此代码未经过测试。我可能错过了分号或一些大括号,但你应该很容易理解。