I have two separate models: Post and Comment. The Comment model has a field called ‘post’ which refers to a post object. I’m using pre
hook in the post model to delete all the comments associated with the post. I’m trying to delete a post from the client side, but only the post itself gets deleted, not the comments. I’m unable to figure out why this is happening.
This is the hook from post model
postSchema.pre("remove", async function (next) {
try {
const commentIds = this.comments.map((comment) => comment.toString());
await this.model("Comment").deleteMany({
_id: {
$in: commentIds,
},
});
next();
} catch (err) {
next(err);
}
});
and this is the route callback function
const deletePost = async (req, res) => {
try {
await Post.findByIdAndRemove(req.params.id);
res.status(200).json({
message: "Post deleted successfully",
});
} catch (error) {
res.status(500).json({
message: "Error deleting post",
});
}
};
2
Answers
The reason this isn’t working as expected is because of the method used to delete the Post document: findByIdAndRemove(). In Mongoose, this method does not trigger the remove middleware, and as a result, the associated comments aren’t being deleted.
The solution to this problem is to first fetch the Post document using findById() and then call the remove() method on the fetched document. This will trigger the remove middleware, and the associated Comment documents will be deleted as expected.
Here’s the updated funtion:
Now, when you delete a post from the client side, both the post and its associated comments will be deleted.
From
Model.findByIdAndRemove()
documentation:So you should use
schema.pre('remove')
hook. One use case of the pre middleware is:And,
Besides, the elements of
this.comments
are all instances ofmongoose.Types.ObjectId
class. You can pass thethis.comments
as the value of$in
operator directly.The below statement is unnecessary
Mongoose also support implicit
$in
:Shorter way:
models/post.js
:models/comment.js
:main.js
:Execution result:
package version:
"mongoose": "^5.11.9"