2

这是我正在尝试做的一个示例,检索 mongo db 中的所有帖子,为每个帖子填充作者,然后使用作者对象从 Cloudinary 检索个人资料图片。

这样做的正确方法是什么?我尝试了多种填充数组并在响应中发送它们的方法,但是由于异步调用,它们在发送 res 之前永远不会运行。

router.get('/posts',auth, function(req, res, next) {
  //var id = req.payload._id;
  Post.find(function(err, posts){
    if(err){ return next(err); }
    posts.forEach(function(post){
      post.populate('author',function(err,post){
        post.image = cloudinary.image("v"+post.author.avatarVersion+"/profile/"+post.author._id,{
          width:100, height:100,crop:'thumb',gravity:'face',radius:'max'
        })
        //here the post object is updated
        console.log(post)
      })
    })
    //res.json(some posts array);
  });
});

感谢 Dan Moldovan 的解决方案!

router.get('/posts',auth, function(req, res, next) {
  var id = req.payload._id;

  Post.find({}).populate('author').exec(function(err,posts){
    if(err){ return next(err); }
    var updatedPosts = [];
    posts.forEach(function(post){
      post.image = cloudinary.image("v"+post.author.avatarVersion+"/profile/"+post.author._id,{
          width:100, height:100,crop:'thumb',gravity:'face',radius:'max'
      })
      updatedPosts.push(post);
    })
    res.json(updatedPosts);
  })
4

2 回答 2

1

您可以将populate查询链接到第一个查询,然后进行最终回调,例如

Post.find({}).populate('author').exec(function (err, posts) {
    if(err){ return next(err); }
    posts.forEach(function(post){
         // here each post will already have author appended
    });
});
于 2015-05-22T20:13:52.170 回答
1

丹的解决方案是正确的,但我想解释一下您遇到的问题。因为post.populate()是数据库调用,就意味着代码是异步的。这意味着 中的下一篇文章forEach()将在上一篇文章完成之前开始运行.populate()。这意味着并非所有帖子都会在res.json()执行之前完成。一个解决方案(在这种情况下不需要,但可以由您当前的代码使用)是使用异步库

var async = require("async");

router.get('/posts',auth, function(req, res, next) {
    var id = req.payload._id;

    Post.find(function (err, posts) {
        if (err) {
            return next(err);
        }

        // This is a forEach that waits until all posts are populated before moving on
        async.each(posts, function (currentPost, postCallback) {

            currentPost.populate("author", function (err, post) {

                if (err) {
                    return postCallback(err);
                }
                post.image = cloudinary.image("v" + post.author.avatarVersion + "/profile/" + post.author._id, {
                    width: 100, height: 100, crop: 'thumb', gravity: 'face', radius: 'max'
                });
                // the callback function for the current post
                postCallback(); 
            });
        }, function (error) {
            // the final callback function once all postCallback()'s have been executed, or an error

            if (error) {
                return next(error);
            }
            // here, everything is finished
            res.json(posts);
        });
    });
});

同样,Dan 的解决方案是正确的,所以不要使用此代码。当您遇到此类问题时,请记住这一点。

于 2015-05-22T20:35:29.423 回答