Mongoose pre.remove middleware of objects in array are never called
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 > test@0.0.1 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.
链接地址: http://www.djcxy.com/p/89572.html