这是Issue https://github.com/Automattic/mongoose/issues/6224的副本 .

我将一个名为FileSpace的嵌入式对象创建为一个名为Space的对象数组 . 删除FileSpace时,永远不会调用预删除中间件(但会调用预验证中间件)

这是一个repro代码:

'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);

输出如下:

$ 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? 我们应该看到日志行:

!!! Calling FileSpace.pre.remove fileKey

Please mention your node.js, mongoose and MongoDB version. 节点9.5.0,Mongoose 5.0.9,MongoDB 3.6.3,Mongo驱动程序:3.0.3

编辑:如果我删除space.files.push(fs)行,正确调用中间件 . 仅当fileSpace放在空间对象的数组中时才会发生pb .