node.js - Mongoose pre.remove 数组中对象的中间件永远不会被调用

标签 node.js mongodb mongoose

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

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

这是一个重现代码:

'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

预期行为是什么? 我们应该看到日志行:

!!! Calling FileSpace.pre.remove fileKey

请提及您的node.js、mongoose 和 MongoDB 版本。 Node 9.5.0、Mongoose 5.0.9、MongoDB 3.6.3、Mongo 驱动程序:3.0.3

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

最佳答案

文档说:

Model.remove() - This method sends a remove command directly to MongoDB, no Mongoose documents are involved. Because no Mongoose documents are involved, no middleware (hooks) are executed.

链接: [https://mongoosejs.com/docs/api.html]

关于node.js - Mongoose pre.remove 数组中对象的中间件永远不会被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49188586/

相关文章:

javascript - Mongodb 检查数组的子文档中是否存在字段

javascript - 使用 mongodb 函数中的字符串

mongodb - mongostat中查询和命令的区别

json - Node.js/Express/Mongoose - 如何发送 JSON 和对象 View ?

javascript - messageReactionAdd 无法添加角色

node.js - PassportJS 认证标志波动

node.js - 提交 Jade 表格

javascript - 在 nodejs 中集成 payUMoney 时出错

java - Spring + java - InspirationTargetException

javascript - 使用 Mongoose 从 MongoDB 检索数据不起作用