Problems with multiple Node.js callbacks

I'm trying to solve a problem i've been having with a nodejs cronjob of mine. So basically, This request grabs my tracks from soundcloud, I loop through the results and put the data in a mongodb collection. This all works great, but now i'm adding another section to the site, so I need to grab some additional info from another collection.

I have a tracks collection, and an inventory collection. The track id is in both collections to relate the additional track data to the newly pulled tracks. So my question is how can I get this additional track data in? Below i have tried to loop through it and inject the data using mongoose's query.find() but the loops do not work together. The callback of the inventory query will run all in one for loop it seems... I'm not exactly sure whats going on there.

I'm pretty sure you can also inject a document from another collection by referencing it in the schema... but i'm unsure of how to get this working. This would obviously be a better solution as it won't require more code like this.

if anybody has any suggestions for me that would be great!

request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
        var o = 1;

        for(i=0; i < body.tracks.length; i++){
            var last = (i + 1);
            var track = body.tracks[i];

            if( track.sharing == 'public'){
                var invData;
                var obj;

                db.model('inventory').find({id:track.id}).exec(function(err,item){
                    //console.log(item[0]);
                    invData = item[0];


                });


                console.log(invData, obj);

                obj = new TracksModel({
                    id: track.id,
                    sharing:track.sharing,
                    uri:track.uri,
                    description:track.description,
                    created_at:track.created_at,
                    duration:track.duration,
                    title:track.title,
                    description:track.description,
                    order: o,
                    inventory_data: invData
                });





                o++;

                obj.save(function (err) {
                    if (!err) {
                        console.log('Track inserted successfully');
                    } else {
                        throw err;
                    }
                });

                if(last == body.length){
                    setTimeout(function(){
                        console.log("Automatically closing database connection after 5 seconds");
                        db.close();
                    }, 5000);
                }

            }

        }

} else {
    console.log('An error has occurred: ', error);
}
});

The way you are treating the query callback is wrong. You are assuming that the code starting from "console.log(invData, obj);" will be executed immediately after the db.model.find. That not the correct notion of Callback. How must put that code inside the exec callback function. You may have to use a closure. Something like:

if (!error && response.statusCode === 200) {
    var o = 1;

    for(i=0; i < body.tracks.length; i++){
        var last = (i + 1);
        var track = body.tracks[i];

        if( track.sharing == 'public'){

            (function(track,last,o){

                var invData;
                var obj;

                db.model('inventory').find({id:track.id}).exec(function(err,item){
                    //console.log(item[0]);
                    invData = item[0];

                    console.log(invData, obj);

                    obj = new TracksModel({
                        id: track.id,
                        sharing:track.sharing,
                        uri:track.uri,
                        description:track.description,
                        created_at:track.created_at,
                        duration:track.duration,
                        title:track.title,
                        description:track.description,
                        order: o,
                        inventory_data: invData
                    });

                    obj.save(function (err) {
                        if (!err) {
                            console.log('Track inserted successfully');
                        } else {
                            throw err;
                        }
                    });

                    if(last == body.length){
                        setTimeout(function(){
                            console.log("Automatically closing database connection after 5 seconds");
                            db.close();
                        }, 5000);
                    }
                });
            }(track,last,o);    

            o++;
        }

    }

}

Try this out:

var utils = require('restberry-utils');

var Inventory = mongoose.model('Inventory');
var Track = mongoose.model('Track');

request({
    url: url,
    json: true
}, function (error, response, body) {
    if (error || response.statusCode !== 200) {
        console.log('An error has occurred: ', error);
        return;
    }
    utils.forEachAndDone(body.track, function(track, iter) {
        if (track.sharing !== 'public') {
            iter();
            return;
        }
        Inventory.findOne({ id: track.id }, function(err, item) {
            new Track({
                id: track.id,
                sharing: track.sharing,
                uri: track.uri,
                description: track.description,
                created_at: track.created_at,
                duration: track.duration,
                title: track.title,
                description: track.description,
                order: o,
                inventory_data: item,
            }).save(function(err) {
                if (err) {
                    throw err;
                } else {
                    console.log('Track inserted successfully');
                    iter();
                }
            })
        });
    }, function() {
        console.log('Done!');
        setTimeout(function() {
            console.log("Automatically closing database connection after 5 seconds");
            db.close();
        }, 5000);
    })
});