0

Something like this

var joined = function(arr) {
    var res = [];
    for (var i in arr) {
        var u = DB.getUser(arr[i].user_id, function(user) {
            return user;
        });
        arr[i].user = u;
        res = arr[i];
    }

    return res;
}

I need to get user variable from DB.getUser scope.

user2194521
  • 119
  • 8
  • 1
    Let me guess. `DB.getUser` is async? – NilsH Apr 17 '13 at 10:27
  • You could also thing about implementing a `getUsers` function. MongoDB has a `$in` selector which allows you to fetch multiple documents in one query. This should be faster and easier. – TheHippo Apr 17 '13 at 11:05

2 Answers2

0
var getJoinedAndDoSomeThingWithThem = function(ids) {
var joined = [];
var i = 0;

var getAUser = function () {
    DB.getUser(ids[i].user_id, function(user) {
        joined.push(user);
        i++;
        if (i == ids.length -1) {
            doSomeThingWithTheResult(joined);
            return;
        }
        getAUser();
    });
}
getAUser();
}
eosterberg
  • 1,422
  • 11
  • 11
0

Is just inserted some comments into you code to help understand the async flow:

var joined = function(arr) {
    // Timestamp: 0
    var res = [];
    for (var i in arr) {
        // Timestamp: 1
        var u = DB.getUser(arr[i].user_id, function(user) {
            // Timestamp 4 ... length of arr
            // user contains what you are looking for
            // but this is not return to u, because we passed that a long time ago
            return user;
        });
        // u is null or undefined, because DB.getUser returns nothing
        // is a async function, you need wait for the callback
        arr[i].user = u;
        // Timestamp: 2 return useless arr
        res = arr[i];
    }
    // Timestamp: 3 again, return a useless array
    return res;
}

Edit:

You need to this before you pass everything to the template, e.g.:

var joined = function(arr, doneCallback) {
    var res = []
    var count = arr.length;
    for (var i in arr) {
        DB.getUser(arr[i].user_id, function(user) {
            count--;
            res.push(user);
            if (count == 0) {
                doneCallback(res);
            }
        })
    }
}

joined(somedata, function(mydata) {
    render(template, mydata)
});

Take a look at some flow control libraries. (My favorite async)

TheHippo
  • 61,720
  • 15
  • 75
  • 100
  • You should do it recursively instead of using a loop - the count variable wont change until the callback is fired. – eosterberg Apr 17 '13 at 10:53
  • @eosterberg: That is the idea. Before the callback is fired there is no result. Therefore we should wait until the last result comes back / the last callback is fired. – TheHippo Apr 17 '13 at 10:55
  • @TheHippo: What if one of the users takes a very long time to get? I meant the count variable in the anonymous callback, not the one in the args. – eosterberg Apr 17 '13 at 11:01
  • @eosterberg: The same thing applies to your own answer ;-) Usually a query will return a time out error, which has to be fetched and handled. I assumed this will happen in the `getUser` function itself. – TheHippo Apr 17 '13 at 11:03
  • @TheHippo: Now I got it! Your answer works fine, and its probably easier to read than mine. – eosterberg Apr 17 '13 at 11:09
  • @eosterberg Glad I could help. As proposed he should write a query that fetches all user. If not it is probably useful to use some flow control library which hides all the counting and managing. – TheHippo Apr 17 '13 at 11:12