使用mongodb查询顺序执行nodejs代码

时间:2015-04-10 09:41:07

标签: node.js mongodb asynchronous callback

我遇到需要从nodejs(expressjs)代码触发mongodb查询的情况,并将查询结果作为对我的web api请求的响应传递,但在我的查询执行之前,下一行代码获取执行并发回空白响应。我写的代码如下,

router.get('/recent', function (req, res){
    var result = [];
    router.db.collection('Posts').find({},{ _id : 1, uid : 1, imagePath : 1, cntLikes : 1, uploadDate : 1}).limit(5).sort({ uploadDate : -1 }).toArray(function(err, docs) {
                docs.forEach( function (doc){
                        router.db.collection('Users').findOne({ "_id" : mongodb.ObjectId(doc.uid)}, function (err, user){
                            doc.username = user;
                            result.push(doc);
                            });
                });


    res.send(result);     // this line send empty result to caller
    });
});

我已经尝试了回调方法,async.waterfall并以编程方式停止执行,但一切都失败了。我也尝试过承诺,但我不认为承诺可以帮助我在这种情况下。

2 个答案:

答案 0 :(得分:1)

您正在循环中使用另一个异步调用,该调用正在res.send(result)之后执行。我认为你所追求的是async.map,所以也许在你的帖子回调中有类似的内容

function addUserToPost(item, callback) {
    router.db.collection('Users').findOne({ "_id" : mongodb.ObjectId(doc.uid)}, function (err, user){
        doc.username = user;
        callback(err, doc);
    });
}

async.map(docs, addUserToPost, function(err, posts) {
    res.send(posts);
});

您希望将“帖子”映射到添加了用户信息的帖子。

答案 1 :(得分:1)

尝试这个:

router.get('/recent', function (req, res){
    var result = [];
    router.db.collection('Posts').find({},{ _id : 1, uid : 1, imagePath : 1, cntLikes : 1, uploadDate : 1}).limit(5).sort({ uploadDate : -1 }).toArray(function(err, docs) {
    var counter = 0;
                docs.forEach( function (doc, index){
                        counter++;
                        router.db.collection('Users').findOne({ "_id" : mongodb.ObjectId(doc.uid)}, function (err, user){
                            doc.username = user;
                            result.push(doc);
                            if(counter === index){
                             res.send(result);    
                            }
                            });
                });        
    });
});