This is a copy of Issue https://github.com/Automattic/mongoose/issues/6224.
I create an Embedded object named FileSpace into an array of object named Space. When removing FileSpace, pre remove middleware is never call (but pre validate middleware is called)
Here is a repro code:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug', true);
/**
* A file
*/
var FileSpaceSchema = new Schema({
fileKey: {
type: String,
required: true
}
});
// Normally called
FileSpaceSchema.pre('validate', function (next) {
console.log('Calling FileSpace.pre.validate me="%s"', this.fileKey);
next();
});
// Never called !
FileSpaceSchema.pre('remove', function(next) {
console.log(' !!! Calling FileSpace.pre.remove fileKey="%s"', this.fileKey);
next();
});
let FileSpace = mongoose.model('FileSpace', FileSpaceSchema);
/**
* A space containing an array of files
*/
var SpaceDocSchema = new Schema({
label: {
type: 'string',
required: true
},
files: [FileSpaceSchema]
});
SpaceDocSchema.pre('validate', function (next) {
console.log('Calling SpaceDocSchema.preValidate hook spaceDoc is "%s"', this.label);
next();
});
SpaceDocSchema.pre('remove', function (next) {
console.log('Calling Space.post.remove spaceDoc is "%s"', this.label);
next();
});
let SpaceDoc = mongoose.model('SpaceDoc', SpaceDocSchema);
console.log('--> Starting');
console.log('--> Creating a space');
let space = new SpaceDoc({
label: 'The SpaceDoc'
}),
removedFile;
// connect to mongo
mongoose.connect('mongodb://mongodbsrv/clouderialTestDB?w=1&j=true');
mongoose.connection.on('open', () => {
console.log('Connection to MongoDB is effective');
space.save()
.then((s) => {
space = s;
console.log('Created space is "%s"', s.label);
console.log('--> Creating a FileSpace');
return new FileSpace({fileKey : 'fileSpace', spaceLabel:'The space label'}).save();
})
.then((fs) => {
console.log('Created FileSpace is "%s"', fs.fileKey);
console.log('--> Add fileSpace into SpaceDoc.files');
space.files.push(fs);
space.markModified('files');
return space.save();
})
.then((s) => {
space = s;
console.log('Updated space is "%s", nbFiles="%d"', space.label, space.files.length);
console.log('--> Remove fileSpace from space');
removedFile = space.files[0];
space.files.splice(0, 1);
// space.files = [];
space.markModified('files');
console.log('--> Update space without file');
return space.save();
})
.then((s) => {
space = s;
console.log('Updated space is "%s", nbFiles="%d"', space.label, space.files.length);
console.log('--> Remove fileSpace');
return removedFile.remove();
})
.then(() => {
console.log('--> Should see the call to pre.remove of FileSpace');
console.log('--> Remove space');
return space.remove();
})
.catch(console.error);
});
setTimeout(() => {
console.log('--> Close MongoDB connection');
mongoose.connection.close();
}, 3000);
The output is the following:
$ npm start > [email protected] start /datas/cld-apps/test > NODE_PATH=/home/vagrant/cld-apps/node_modules:. TZ=Europe/Paris node test.js --> Starting --> Creating a space Connection to MongoDB is effective Calling SpaceDocSchema.preValidate hook spaceDoc is "The SpaceDoc" Mongoose: spacedocs.insert({ label: 'The SpaceDoc', files: [], _id: ObjectId("5aa18e47f13311778fdc3beb"), __v: 0 }) Created space is "The SpaceDoc" --> Creating a FileSpace Calling FileSpace.pre.validate me="fileSpace" Mongoose: filespaces.insert({ fileKey: 'fileSpace', _id: ObjectId("5aa18e47f13311778fdc3bec"), __v: 0 }) Created FileSpace is "fileSpace" --> Add fileSpace into SpaceDoc.files Calling SpaceDocSchema.preValidate hook spaceDoc is "The SpaceDoc" Calling FileSpace.pre.validate me="fileSpace" Mongoose: spacedocs.update({ _id: ObjectId("5aa18e47f13311778fdc3beb"), __v: 0 }, { '$set': { files: [ { fileKey: 'fileSpace', _id: ObjectId("5aa18e47f13311778fdc3bec"), __v: 0 } ] }, '$inc': { __v: 1 } }) Updated space is "The SpaceDoc", nbFiles="1" --> Remove fileSpace from space --> Update space without file Calling SpaceDocSchema.preValidate hook spaceDoc is "The SpaceDoc" Mongoose: spacedocs.update({ _id: ObjectId("5aa18e47f13311778fdc3beb"), __v: 1 }, { '$set': { files: [] }, '$inc': { __v: 1 } }) Updated space is "The SpaceDoc", nbFiles="0" --> Remove fileSpace --> Should see the call to pre.remove of FileSpace --> Remove space Calling Space.post.remove spaceDoc is "The SpaceDoc" Mongoose: spacedocs.remove({ _id: ObjectId("5aa18e47f13311778fdc3beb") }, {}) --> Close MongoDB connection
What is the expected behavior? We should see the log line:
!!! Calling FileSpace.pre.remove fileKey
Please mention your node.js, mongoose and MongoDB version. Node 9.5.0, Mongoose 5.0.9, MongoDB 3.6.3, Mongo driver: 3.0.3
EDIT : if I remove the space.files.push(fs) line, the middleware is correctly called. The pb occurs only if fileSpace is put in the array of space object.