JS - Express - Mongoose在发送响应之前执行所有mongoose的承诺

时间:2013-12-18 23:46:35

标签: javascript node.js express mongoose forum

我正在做论坛api,论坛有很多帖子,帖子有很多帖子,帖子可能有很多帖子。

关系是这样完成的:

var PostSchema = new Schema({
  text: String,
  authorId: String,
  slug: Number,
  posts: [{ type: Schema.Types.ObjectId, ref: 'Post'}],
  created: { type: Date, default: Date.now }
});

父模型有一个儿子模型的ID列表。

我的控制器是这样的:

var util = require('util'),
  mongoose = require('mongoose'),
  Forum = mongoose.model('Forum'),
  Thread = mongoose.model('Thread'),
  Post = mongoose.model('Post'),
  async = require('async');

exports.show = function(req, res){
  var forums;

  var getThreads = function(forum) {
    return forum.populate('threads', function(err, _forum){
      if(err) throw new Error(err);
      forum.threads = _forum.threads;
      forum.threads.forEach(getPosts);
      return callback(err);
    }); 
  };

  var getPosts = function(thread) {
    return thread.populate('posts', function(err, _thread){
      if(err) throw new Error(err);
      thread.posts = _thread.posts;
      thread.posts.forEach(getComments);
      return callback(err);
    });
  };

  var getComments = function(post) {
    return post.populate('posts', function(err, _post){
      if(err) throw new Error(err);
      post.posts = _post.posts;
      post.posts.forEach(getComments);
      return callback(err);
    });
  };

  async.parallel([
    function(callback) {
      return Forum.find({ ownerId: req.params.owner_id }).exec(function(err, _forums) {
        if(err) throw new Error(err);
        forums = _forums;
        forums.forEach(getThreads);
        return callback(err);
      });
    }
  ], function(err){
      res.json(forums);
    }
  );

};

我需要制作完整的论坛对象,然后在回复中使用它,因为帖子有帖子我不能只做一个嵌套的填充。

我尝试使用异步lib,但它在promises之前执行回调函数。

如何构建完整的论坛对象?

2 个答案:

答案 0 :(得分:1)

您需要以异步方式正确处理树结构。试试这种方法:

(我没有测试,但希望它有效)

// ...
var Forum = mongoose.model('Forum');

exports.show = function(req, res){
  //Get the owner's forums
  Forum.find({ ownerId: req.params.owner_id }).exec(function(err, forums) {
    if(err) throw new Error(err);
    if(!forums.length) return response.json(forums); //Send an empty array if no forums where found

    //Build forums one by one
    var forum = forums.shift();
    buildForum(forum, function () {
      forum = forums.shift();
      if (forum) {
        buildForum(forum, this);
      } else {
        //All forums were built.
        res.json(forums);
      };
    });
  });

  var buildForum = function (forum, onSuccess) {
    forum.populate('threads', function(err, forum){
      if(err) throw new Error(err);
      if(!forum.threads.length) return onSuccess();

      //Build threads one by one
      var threads = forum.threads;
      var thread = threads.shift();
      buildThread(thread, function () {
        thread = threads.shift();
        if (thread) {
          buildThread(thread, this);
        } else {
          //All threads were built.
          onSuccess();
        };
      });
    });
  };

  var buildThread = function (thread, onSuccess) {
    thread.populate('posts', function(err, thread){
      if(err) throw new Error(err);
      if(!thread.posts.length) return onSuccess();

      //Build posts one by one
      var posts = thread.posts;
      var post = posts.shift();
      buildPost(post, function () {
        post = posts.shift();
        if (post) {
          buildPost(post, this);
        } else {
          //All posts were built.
          onSuccess();
        };
      });
    });
  };

  var buildPost = function (post, onSuccess) {
    post.populate('posts', function(err, post){
      if(err) throw new Error(err);
      if(!post.posts.length) return onSuccess();

      //Build comments one by one
      var posts = post.posts;
      var _post = posts.shift();
      buildPost(_post, function () {
        _post = posts.shift();
        if (_post) {
          buildPost(_post, this);
        } else {
          //All comments were built.
          onSuccess();
        };
      });
    });
  };
}; 

答案 1 :(得分:1)

这是我的解决方案,只是@Danypype解决方案中的一个小修复。

exports.show = function(req, res){
  //Get the owner's forums
  Forum.find({ ownerId: req.params.owner_id }).exec(function(err, forums) {
    if(err) throw new Error(err);
    if(!forums.length) return response.json(forums); //Send an empty array if no forums where found

    //Build forums one by one
    var forum = forums.shift();  
    var responseForums = [forum];

    buildForum(forum, function () {
      forum = forums.shift();
      if (forum) {
        responseForums.push(forum);
        buildForum(forum, arguments.callee);
      } else {
        //All forums were built.
        res.json(responseForums);
      };
    });
  });

  var buildForum = function (forum, onSuccess) {
    forum.populate('threads', function(err, forum){
      if(err) throw new Error(err);
      if(!forum.threads.length) return onSuccess();
      if(forum.length == 1) return onSuccess();

      var thread = forum.threads.shift();
      var responseThreads = [thread];

      buildThread(thread, function () {
        thread = forum.threads.shift();
        if (thread) {
          responseThreads.push(thread)
          buildThread(thread, arguments.callee);
        } else {
          //All threads were built.
          forum.threads = responseThreads;
          onSuccess();
        };
      });
    });
  };

  var buildThread = function (thread, onSuccess) {
    thread.populate('posts', function(err, thread){
      if(err) throw new Error(err);
      if(!thread.posts.length) return onSuccess();

      var post = thread.posts.shift();
      var responsePosts = [post]

      buildPost(post, function () {
        post = thread.posts.shift();
        if (post) {
          responsePosts.push(post);
          buildPost(post, arguments.callee);
        } else {
          //All posts were built.
          thread.posts = responsePosts;
          onSuccess();
        };
      });
    });
  };

  var buildPost = function (post, onSuccess) {
    post.populate('posts', function(err, post){
      if(err) throw new Error(err);
      if(!post.posts.length) return onSuccess();

      //Build comments one by one
      var _post = post.posts.shift();
      var response_posts = [_post];

      buildPost(_post, function () {
        _post = post.posts.shift();
        if (_post) {
          response_posts.push(_post);
          buildPost(_post, arguments.callee);
        } else {
          //All comments were built.
          post.posts = response_posts;
          onSuccess();
        };
      });
    });
  };
};