Search code examples
javascriptnode.jsmongodbmongoosemongoose-schema

Mongoose add schema into schema using method


I am trying to build a blog that uses Node.js as server-side language, with Mongo DB.

So in my blog people can write posts and add comments to posts just like other blogs.

Each post will have comments, that's what I am trying with my post schema. When someone tries to write a comment on a post, it will send a POST request to the server, create a new comment and save it into database.

Comment itself is being saved properly when I am testing, but I am having a trouble with attaching it into post schema.

Here is my postSchema.js:

const mongoose = require("mongoose");

const postSchema = new mongoose.Schema(
  {
    owner: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true
    },
    title: {
      type: String,
      required: true
    },
    body: {
      type: String,
      required: true
    },
    comments: [
      {
        comment: {
          type: mongoose.Schema.Types.ObjectId,
          ref: "Comment"
        }
      }
    ]
  }
);

And my commentSchema.js:

const mongoose = require("mongoose");

const commentSchema = new mongoose.Schema(
  {
    owner: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true
    },
    post: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Post",
      required: true
    },
    content: {
      type: String,
      required: true
    }
  }
);

module.exports = Comment = mongoose.model("Comment", commentSchema);

So post schema has comments array to store comments in it. And everytime a user adds a comment, it will create a POST request:

router.post("/:id/new_comment", async (req, res) => {
  const { content } = req.body;
  const comment = new Comment({
    content,
    owner: req.user._id,
    post: req.params.id
  });
  try {
    const post = await Post.findOne({ _id: req.params.id });
    await comment.save();
    await post.addComment(comment);
    res.status(201).send({ post, comment });
  } catch (error) {
    res.status(500).send({ error: error.message });
  }
});

So this POST request will look for the post to add the comment, save the comment, and call addComment() to concatenate the comment into the comments array of the post. Comment created here will be used as the parameter for addComment() function.

And addComment() function is inside the PostSchema.js file and it is:

postSchema.methods.addComment = async function(comment) {
  const post = this;
  post.comments = post.comments.concat({ comment });
  await post.save();
  return post;
};

Everything works fine, but the result is different from I expected. I expected it to be like

{
    "post": {
        "_id": "5e2e94c9e6ef8100ecfaf665",
        "title": "Test Post",
        "body": "Test Body",
        "owner": "5e2e6bbd18929829e8679cec",
        "comments": [
            {
                "_id": "5e2e98d9587c78444cd600b2",
                "comment": {
                    "_id": "5e2e98d9587c78444cd600b1",
                    "content": "Test Comment",
                    "owner": "5e2e6bbd18929829e8679cec",
                    "post": "5e2e94c9e6ef8100ecfaf665",
                    "__v": 0
                }
            }
        ],
    },
    "comment": {
        "_id": "5e2e98d9587c78444cd600b1",
        "content": "Test Comment",
        "owner": "5e2e6bbd18929829e8679cec",
        "post": "5e2e94c9e6ef8100ecfaf665",
        "__v": 0
    }
}

It looks fine at the first but the problem comes in when I try to save the second comment. The comment saved before changes somehow, like below:

{
    "post": {
        "_id": "5e2e94c9e6ef8100ecfaf665",
        "title": "Test Post",
        "body": "Test Body",
        "owner": "5e2e6bbd18929829e8679cec",
        "comments": [
            {
                "_id": "5e2e98d9587c78444cd600b2",
                "comment": "5e2e98d9587c78444cd600b1"
            },
            {
                "_id": "5e2e98d9587c78444cd600b3",
                "comment": {
                    "_id": "5e2e98d9587c78444cd600b2",
                    "content": "Test Comment 2",
                    "owner": "5e2e6bbd18929829e8679cec",
                    "post": "5e2e94c9e6ef8100ecfaf665",
                    "__v": 0
                }
            }
        ],
    },
    "comment": {
        "_id": "5e2e98d9587c78444cd600b2",
        "content": "Test Comment 2",
        "owner": "5e2e6bbd18929829e8679cec",
        "post": "5e2e94c9e6ef8100ecfaf665",
        "createdAt": "2020-01-27T08:01:29.492Z",
        "updatedAt": "2020-01-27T08:01:29.492Z",
        "__v": 0
    }
}

As I created Test Comment 2, the first comment I saved changed. What possibly can cause this? Thanks for reading such a long question. Any help will be appreciated! Have a nice day.


Solution

  • Problem is here you are passing your full comment instead of it's id.

      await post.addComment(comment_id); // pass comment id here 
    

    Because in your post model

    comments: [
          {
            comment: {
              type: mongoose.Schema.Types.ObjectId, // you are storing ObjectId here 
              ref: "Comment"
            }
          }
        ]
    

    So, you can store your comments as array of your comment id and then you can get your full comments when you want to populate it