Search code examples
javascriptnode.jsmongodbmongoskin

NodeJs MongoDB Nested Queries - Run Callback Synchronously


I have a code block like below. I could not find how to achieve that.
- I have rooms collection in mongodb and documents in this collection include user id array. Each room can have multiple users.
- So I want to find that usernames which are in the rooms that include my user Id.

DB collections:
Rooms {roomId:1, users:[99, 100]}, {roomId:2, users:[99, 101]}
Users {_id:99, name:"Alex"},{_id:100, name:"Harry"},{_id:101, name:"Tom"}

var userId = 99;
var arrUserIds = [];
var arrRooms = [];
var strUserNames = "";
db.collection("rooms").find({"users.userId":userId}).toArray(function(err, rooms) {

    for (var i=0; i<rooms.length; i++) {
        arrUserIds = [];

        for(var j=0; j<rooms[i].users.length; j++){
            arrUserIds.push(new BSON.ObjectID(rooms[i].users[j].userId));   
        }

        db.collection('users').find({"_id": {$in: arrUserIds}}).toArray(function(err, users) {
            strUserNames = users.map(function(elem){return elem.name;}).join(", ");
            arrRooms.push({_id:rooms[i].roomId, name:strUserNames });
        });

    }

    res.json({rooms:arrRooms});
});

I want to have a result like that:
arrRooms: [ { _id:1:, name:"Alex, Harry" }, { _id:2:, name:"Alex, Tom" } ]

Thanks


Solution

  • You're returning res.json before the second .find callback executes, so it will be empty. You need to restructure to wait for all the async callbacks before responding, like so:

    var userId = 99;
    var arrRooms = [];
    var strUserNames = "";
    
    db.collection("rooms").find({"users.userId":userId}).toArray(function(err, rooms) {
    
        var completed = 0;
        var complete = function() {
            completed++;
            if (completed === rooms.length - 1) {
                res.json({rooms:arrRooms});
            }
        }
    
    
        for (var i=0; i<rooms.length; i++) {
            var arrUserIds = [];
            var roomId = rooms[i].roomId;
    
            for(var j=0; j<rooms[i].users.length; j++){
                arrUserIds.push(new BSON.ObjectID(rooms[i].users[j].userId));   
            }
    
            db.collection('users').find({"_id": {$in: arrUserIds}}).toArray(function(err, users) {
                strUserNames = users.map(function(elem){return elem.name;}).join(", ");
                arrRooms.push({_id:roomId, name:strUserNames });
    
                complete();
            });
        }
    
    });