3

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.

1 Answer 1

0

The documentation says:

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.

Link: [https://mongoosejs.com/docs/api.html]

Sign up to request clarification or add additional context in comments.

1 Comment

Hello, If you're going quote from Documentation it is recommended to also link to the page which you quoted from so that others can read more deeply if needed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.