Boy Boy - 1 month ago 13
Node.js Question

expressjs mongodb find query loop with queries inside

So I am using this query to create an array to pass on to ejs to generate table rows. but before I pass it, I have other queries like referencing ids or count. but I get undefined on count. I may have other queries inside.

router.get('/', function(req, res, next) {
MongoClient.connect(MongoUrl, function(err, db) {

var table_data = [];
db.collection('categories').find().toArray(function(err, result) {

for (var i = 0, len = result.length; i < len; i++) {
var count;
db.collection('articles').count({category_id: result[i].category_id}, function(err, count) {
count = count;
});

table_data[i] = {
"category_id" : result[i].category_id,
"category" : result[i].category,
"count" : count,
"date_last_imported" : result[i].date_last_imported,
"feed" : result[i].feed,
"url" : result[i].url,
"xml" : result[i].xml
};

}
console.log(table_data);
res.render('categories', {title:"Categories",table_data: table_data});
});
});
});

Answer

It's because count is not yet fetched and you have pushed it in array that is undefined. If you have lot of queries inside queries then in that case you'll be trapped in callback hell. To get out of this scenario either use promise or use "async"module.

For reference: http://caolan.github.io/async/

For current scenario and to get idea why "count" is undefined:

router.get('/', function(req, res, next) {
    MongoClient.connect(MongoUrl, function(err, db) {

        var table_data = [];
        db.collection('categories').find().toArray(function(err, result) {

            for (var i = 0, len = result.length; i < len; i++) {
                var count;
                db.collection('articles').count({category_id: result[i].category_id}, function(err, count) {
                    count = count;
                table_data.push( {
                    "category_id" : result[i].category_id,
                    "category" : result[i].category,
                    "count" : count,
                    "date_last_imported" : result[i].date_last_imported,
                    "feed" : result[i].feed,
                    "url" : result[i].url,
                    "xml" : result[i].xml
                });
             if(table_data.length === result.length) {
               res.render('categories', {title:"Categories",table_data:  table_data});
             }
                 });



            }

        });
    });
});

UPDATE: To get out of inner queries.

router.get('/', function(req, res, next) {
    MongoClient.connect(MongoUrl, function(err, db) {
        var table_data = [];
        db.collection('categories').find().toArray(function(err, result) {
          async.each(result, function (user, cb) {
            async.waterfall([
              function (cb) {
                db.collection('articles').count({
                    category_id: result[i].category_id
                }, function(err, count) {
                    cb(err, count);
                });
              },
              function (count, cb) {
                //another query
                cb(err, count, secondquerydata);
              },
              .....
            ], function (err, count, secondquerydata, .....) {
              if(err) return callback(err);
              // here use your all query data
              table_data.push( {
                  "category_id": result[i].category_id,
                  "category": result[i].category,
                  "count": count,
                  "date_last_imported": result[i].date_last_imported,
                  "feed": result[i].feed,
                  "url": result[i].url,
                  "xml": result[i].xml
              });
              res.render('categories', {
                  title: "Categories",
                  table_data: table_data
              });
            })
          })

        });
    });
});