Jacob K Jacob K - 6 months ago 25
Node.js Question

Fetch from multiple, separate, collections with Express and MongoDB

I have a site where i need some data from my Mongo data to be shown. My problem, however, is that i need data from two collections. Collections that are completely separate and have nothing to do with each other.

Right now i have this in my routes for my profile-page:

router.get('/profile', function(req, res,next) {
var resultArray = [];

mongo.connect(url, function(err, db) {
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err) {
resultArray.push(doc);
}, function() {
db.close();
res.render('profile/index', {users: resultArray});
});
});
});


And this, of course, works perfectly fine. But how do i get a second
db.collection('colors').find();
to be passed along to my template too?

I'm sure it's something trivial, and me just not quite having the full grasp of things, but yeah.. I'm stuck..

Answer

Use the async library which is best suited for this scenario. Where you need to run multiple tasks that do not depend on each other and when they all finish do something else, you should use async.parallel() method. The signature is async.parallel(tasks, callback), where tasks is an array of functions.

It will immediately run all the functions in parallel, wait for all of them to call their task callback, and finally when all tasks are complete it will run callback (the final callback).

The following example demonstrates how this could be adapted for your use case:

router.get('/profile', function(req, res, next) {
    mongo.connect(url, function(err, db) {
        var locals = {};
        var tasks = [
            // Load users
            function(callback) {
                db.collection('users').find({}).toArray(function(err, users) {
                    if (err) return callback(err);
                    locals.users = users;
                    callback();
                });
            },
            // Load colors
            function(callback) {
                db.collection('colors').find({}).toArray(function(err, colors) {
                    if (err) return callback(err);
                    locals.colors = colors;
                    callback();
                });
            }
        ];

        async.parallel(tasks, function(err) { //This function gets called after the two tasks have called their "task callbacks"
            if (err) return next(err); //If an error occurred, let express handle it by calling the `next` function
            // Here `locals` will be an object with `users` and `colors` keys
            // Example: `locals = {users: [...], colors: [...]}`
            db.close();
            res.render('profile/index', locals);
        });
    });
});