Skip to content

Pre-remove hooks not called for subdocuments #9885

@TimUnderhay

Description

@TimUnderhay

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
Pre-remove middleware is not called when removing an item from an array of subdocuments. According to #6224, this seemed to work with Mongoose <5.0.0. @vkarpov15 asked @georgehess to open a new issue on this in the same #6224, though it appears not to have happened, thus I'm running it up the flagpole.

This behaviour presents a problem for me because I need to know when a document is removed from an array, so that a corresponding cache entry can be deleted. Unfortunately, modifiedPaths doesn't provide enough context to tell me when something is removed, only that something happened. I can, of course, clear the cache entry manually from outside of my Mongoose code, but this seems like a less-than-elegant solution.

If the current behavior is a bug, please provide the steps to reproduce.

const mongoose = require('mongoose');

const SubSchema = mongoose.Schema({
  myValue: {
    type: String
  }
}, {});

SubSchema.pre('remove', async function() {
  console.log('Subdoc got removed!')
});



const Schema = mongoose.Schema({
  foo: {
    type: String,
    required: true
  },
  mySubdoc: {
    type: [SubSchema],
    required: true
  }
}, {minimize: false, collection: 'test'});

const Model = mongoose.model('TestModel', Schema);


const initMongoose = async () => {
  const mongooseUrl = `mongodb://user:pass@dbhost:27017/test`;
  try {
    await mongoose.connect(mongooseUrl, {
      useUnifiedTopology: true,
      useNewUrlParser: true,
      promiseLibrary: global.Promise,
      useFindAndModify: false
    });
  }
  catch (err) {
    console.error(err);
    process.exit(1);
  }
  console.log('Connected');
};


const test = async () => {
  await Model.deleteMany({}); // remove all existing documents
  const newModel = {
    foo: 'bar',
    mySubdoc: [{myValue: 'some value'}]
  };
  const document = await Model.create(newModel);
  console.log('Created document');
  console.log('document:', document);
  
  console.log('Removing subDocument');
  document.mySubdoc[0].remove();
  
  
  console.log('Saving document');
  await document.save().catch( (error) => {
    console.error(error);
    process.exit(1);
  });
  console.log('document:', document);

  console.log(`Notice that SubSchema.pre('remove') never ran`);
};



const main = async () => {
  await initMongoose();
  await test();
  process.exit(0);
};

main();

Output from the above is:

Connected
Created document
document: {
  _id: 601831bcddc22e01c640d6b6,
  foo: 'bar',
  mySubdoc: [ { _id: 601831bcddc22e01c640d6b7, myValue: 'some value' } ],
  __v: 0
}
Removing subDocument
Saving document
document: { _id: 601831bcddc22e01c640d6b6, foo: 'bar', mySubdoc: [], __v: 1 }
Notice that SubSchema.pre('remove') never ran

What is the expected behavior?
Pre-remove hooks should run when removing sub-documents.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Mongoose 5.11.14
Node.js 15.5.1
MongoDB 4.4.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions