Skip to content Skip to sidebar Skip to footer

Mongoose & Express: How To Properly Remove, Create & Store Data That Are Reference

The first problem I am having is that whenever I try to delete the Comment, I also try to find the index of that specific comment inside post.comments as well as inside user.commen

Solution 1:

I think you need to redesign your schemas in a simpler way, there are too many references between the models, and this causes issues, for example you have 5 db access when you want to create a comment, and 6 db access when you want to delete a comment.

I would create the user schema like this removing the posts and comment references, but later when we want to access the posts from users, I set up virtual populate.

constUserSchema = newSchema(
  {
    name: {
      type: String,
      required: true
    },
    email: {
      type: String,
      required: true,
      unique: true
    },
    password: {
      type: String,
      required: true
    },
    avatar: {
      type: String
    },
    date: {
      type: Date,
      default: Date.now
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

UserSchema.virtual("posts", {
  ref: "Post",
  localField: "_id",
  foreignField: "user"
});

And in the posts schema, I removed the comments references. (For simplicity I removed likes and dislikes fields.)

constPostSchema = newSchema(
  {
    user: {
      type: Schema.Types.ObjectId,
      ref: "User"
    },
    text: {
      type: String,
      required: true
    },
    date: {
      type: Date,
      default: Date.now
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

PostSchema.virtual("comments", {
  ref: "Comment",
  localField: "_id",
  foreignField: "post"
});

Comment schema can stay as it is.

Now to add a comment to a post, we only need 2 db access, one for checking if post exists, and one for creating the post.

router.post(
  "/comment/:id",
  [
    auth,
    [
      check("text", "Text is required")
        .not()
        .isEmpty()
    ]
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    try {
      const post = awaitPost.findById(req.params.id);
      if (!post) {
        return res.status(404).json({ msg: "Post not found" });
      }

      let comment = newComment({
        text: req.body.text,
        post: req.params.id,
        user: req.user.id
      });

      comment = await comment.save();

      res.json(comment);
    } catch (err) {
      console.error(err.message);
      res.status(500).send("Server Error");
    }
  }
);

Let's say we have these 2 users:

{
    "_id" : ObjectId("5e216d74e7138b638cac040d"),
    "name" : "user1"
}
{
    "_id" : ObjectId("5e217192d204a26834d013e8"),
    "name" : "user2"
}

User1 with _id:"5e216d74e7138b638cac040d" has this post.

{"_id":"5e2170e7d204a26834d013e6","user":"5e216d74e7138b638cac040d","text":"Post 1","date":"2020-01-17T08:31:35.699Z","__v":0,"id":"5e2170e7d204a26834d013e6"}

Let's say user2 with _id:"5e217192d204a26834d013e8" commented on this post two times like this:

{
    "_id" : ObjectId("5e2172a4957c02689c9840d6"),
    "text" : "User2 commented on user1 post1",
    "post" : ObjectId("5e2170e7d204a26834d013e6"),
    "user" : ObjectId("5e217192d204a26834d013e8"),
    "date" : ISODate("2020-01-17T11:39:00.396+03:00"),
    "__v" : 0
},
{
    "_id": "5e21730d468bbb7ce8060ace",
    "text": "User2 commented again on user1 post1",
    "post": "5e2170e7d204a26834d013e6",
    "user": "5e217192d204a26834d013e8",
    "date": "2020-01-17T08:40:45.997Z",
    "__v": 0
}

To remove a comment we can use the following route, as you see we decreased the db access from 6 to 3, and code is shorter and cleaner.

router.delete("/comment/:id/:comment_id", auth, async (req, res) => {
  try {
    const comment = awaitComment.findById(req.params.comment_id);

    if (!comment) {
      return res.status(404).json({ msg: "Post do not have this comment" });
    }

    if (comment.user.toString() !== req.user.id) {
      return res.status(401).json({ msg: "User not authorized" });
    }

    await comment.remove();

    // resend the comments that belongs to that postconst postComments = awaitComment.find({ post: req.params.id });
    res.json(postComments);
  } catch (err) {
    console.error(err.message);
    res.status(500).send("Server Error");
  }
});

Now you may ask, how will access the posts from an user? Since we setup virtual populate in our user schema, we can populate the posts like this:

router.get("/users/:id/posts", async (req, res) => {
  const result = awaitUser.findById(req.params.id).populate("posts");

  res.send(result);
});

Solution 2:

You can try this code snipet :

Comment.deleteOne({
_id: comment.id
}, function (err) {
if (err) {
  console.log(err);
  return res.send(err.message);
}
res.send('success');
});

Post a Comment for "Mongoose & Express: How To Properly Remove, Create & Store Data That Are Reference"