在NodeJS MongoDB中保留嵌套for循环和回调中的执行顺序

时间:2014-05-19 06:56:41

标签: javascript node.js node-mongodb-native

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)来处理执行顺序,但它似乎在这里似乎不起作用。 任何帮助表示赞赏。 感谢

1 个答案:

答案 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();
});

您应该知道此代码未经过测试。我可能错过了分号或一些大括号,但你应该很容易理解。