Search code examples
javascriptnode.jsmongodbexpressmongoose-schema

How would I populate the mongoDB post schema with all comments for post?


I have build two schemas, one for posts and one for comments.

const PostSchema = new Schema(
  {
    title: { type: String, required: true },
    text: { type: String, required: true },
    author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
    status: { type: Boolean, default: true },
  },
  { timestamps: true }
);

, and:

const CommentSchema = new Schema(
  {
    text: { type: String, required: true, minlength: 5 },
    author: { type: String, required: true },
    post: { type: Schema.Types.ObjectId, ref: 'Post' },
  },
  {
    timestamps: true,
  }
);

Now I want to make a GET request which finds all posts and would populate each post with its comments. So far I have this, but I am hitting a wall. If I try to do it like this, I can't add .toArray(), and it doesn't even add new field to the allPosts.

exports.allPosts_GET = (req, res) => {
  Post.find()
    .populate('author')
    .sort('-createdAt')
    .exec((err, allPosts) => {
      if (err) {
        return res.status(500).json({ success: false, msg: err.message });
      } else if (allPosts.length === 0) {
        return res.status(404).json({
          success: false,
          msg: 'No posts find in the database!',
        });
      }
      
      allPosts.map((post) => {
        post.comments = Comment.find({post: post._id}). 
        //to array somehow and populate all posts
        
      });

      console.log(allPostsStore);

      res.status(200).json({ success: true, posts: allPosts });
    });
};

Solution

  • So I came up with a solution, I updated my Post schema that contains an array with reference to ids of comments. Like that:

    const PostSchema = new Schema(
      {
        title: { type: String, required: true },
        text: { type: String, required: true },
        author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
        comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }],
        status: { type: Boolean, default: true },
      },
      { timestamps: true }
    );
    

    And then when you make a new comment, you reference it to a post, and also save it to array of comments, like that:

    exports.createNewComment_POST = (req, res) => {
      const { text, author, postID } = req.body;
    
      const newComment = new Comment({
        text,
        author,
        post: postID,
      });
    
      newComment
        .save()
        .then((comment) => {
          Post.findByIdAndUpdate(
            postID,
            { $push: { comments: comment._id } },
            { new: true, useFindAndModify: false },
            (err, post) => {
              if (err) {
                return res.status(500).json({ success: false, msg: err.message });
              }
              res.status(200).json({ success: true, comment });
            }
          );
        })
        .catch((err) => {
          res.status(500).json({ success: false, msg: err.message });
        });
    };
    

    Getting all posts with their comments, you just use find() and populate(), like that:

    exports.allPosts_GET = (req, res) => {
      Post.find()
        .populate('author', '-password')
        .populate('comments')
        .sort('-createdAt')
        .exec((err, posts) => {
          if (err) {
            return res.status(500).json({ success: false, msg: err.message });
          } else if (posts.length === 0) {
            return res.status(404).json({
              success: false,
              msg: 'No posts find in the database!',
            });
          }
          res.status(200).json({ success: true, posts: posts });
        });
    };