mongoose: Remove hook not triggered when removing documents

The pre/post hooks for remove are only triggered when using the document instance’s remove() method, not when the model’s methods are used:

var mongoose = require("mongoose");
var db = mongoose.createConnection('mongodb://localhost/experiment');
db.once('open', function(){

  testSchema = new mongoose.Schema({ title: String });
  testSchema.post('remove', function(removed){
    console.log('removed', removed.title);
  });
  var Test = db.model('Test', testSchema);

  // > "removed A"
  new Test({ title: 'A' }).save(function(err, created){
    created.remove();
  });

  // Nothing :(
  Test({ title: 'B' }).save(function(err, created){
    Test.remove({ title: 'B' }).exec();
  });

  // Nothing :(
  Test({ title: 'C' }).save(function(err, created){
    Test.find({ title: 'C' }).remove();
  });

});

About this issue

  • Original URL
  • State: closed
  • Created 12 years ago
  • Comments: 24 (6 by maintainers)

Most upvoted comments

This is how I got around the issue:

Post.findOneAndRemove({'id': data.post, 'user.uid': socket.handshake.user.id}, function(err, post) {
    post.remove();
});

models.js

postSchema.post('remove', function(doc) {
    console.log('removed');
});

// prints 'removed' once

The remove hook is not fired on findOneAndRemove, however, it works when I call remove in the callback

Ok but Why ? iam sorry i didnt get why the hook is executed on Model.remove() and not on Query.remove(). Now why should i use the hooks if they arent called everytime ?
what’s the use ?

@Darksheep42 if you want to use hooks, use doc.remove(). The reason why things like MyModel.remove(); doesn’t support hooks is that the removed document may not exist in memory, so you would first have to query mongodb for the document and then tell mongodb to remove it for hooks to work properly.

Seems like a reasonable idea, but I’m hesitant to break API unless there’s a really good reason to. Right now the remove hook operates on a document, so the context in the middleware is the document. For general Query.remove(), the document might not even be in memory. I suppose we could name it something else like 'remove-query, but that's nasty. What do you think about adding an extra options arg topre()andpost()`, something like:

schema.pre('remove', { query: true }, function() {
  // This is only attached as query middleware
});

schema.pre('remove', { doc: true }, function() {
  // This will not run on Query.remove(), only doc.remove()
});

The issue of pre remove for documents vs queries is tracked in #3054, not implemented yet, PRs welcome.