简体   繁体   English

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

[英]Preserving Execution order in nested for loop and callbacks in NodeJS MongoDB

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:

users is array having user info. users是具有用户信息的数组。

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);                        
}

Now, the execution order is preserved up to Level-2, but when it enters Level-3, all things just go wrong: I have two users in array and one user has 3 posts and another has 10 posts, sometimes response is only 3 posts and sometimes all the 13 posts. 现在,执行顺序一直保留到Level-2,但是当它进入Level-3时,一切都出错了:我在阵列中有两个用户,一个用户有3个帖子,另一个用户有10个帖子,有时响应只有3个帖子,有时是全部13个帖子。 I think its because of MongoDB. 我认为这是因为MongoDB。 I am even taking care of execution order by using immediately invoked function expression(IIFE), but it just does not seem to work here. 我什至通过使用立即调用的函数expression(IIFE)来照顾执行顺序,但在这里似乎不起作用。 Any help is appreciated. 任何帮助表示赞赏。 Thanks 谢谢

First of all you should beautify your code. 首先,您应该美化您的代码。 Using anonymous functions inside loops inside callbacks of other loops is not really easy to maintain or read. 在其他循环的回调内部的循环内部使用匿名函数并不容易维护或读取。

The problem with your code was that in the last loop ( the j loop ) you get to j == users.length - 1 before queries for others users were finished so the response is sent with the number of post queries finished until that moment. 您的代码的问题在于,在最后一个循环(j循环)中,在完成对其他用户的查询之前,您进入j == users.length-1,因此,发送该请求之前的查询数量已完成。

One other big mistake you made was that you request the post collection inside a loop. 您犯的另一个大错误是您在一个循环中请求了post集合。 That's wrong! 错了! You should cache both the database and the collection. 您应该同时缓存数据库和集合。

Try this code: 试试这个代码:

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

You should know that this code is not tested. 您应该知道此代码未经测试。 I might have missed a semicolon or some braces but you should figure that out easily. 我可能错过了分号或花括号,但您应该轻松弄清楚。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM