猫鼬子文档预删除未调用的中间件

Mongoose sub document pre remove middleware not called

我会阻止删除任何子文档,因此我在每个子文档架构的 pre('remove') 中间件中添加了一个错误。

调用.remove()函数时,实际上是调用了中间件。但是在不调用remove()的情况下删除时,中间件不会检查是否已经删除。

重要的情况是当我从远程源接收到一个对象时,我想通过 mongoose 中间件执行所有完整性检查以将所有内容保持在同一个位置。无论是否有误,远程源都可能删除了其中一个子文档。所以当 Mongoose 检查整个文档时,子文档已经被删除而没有触发 .remove() 函数。

这是我的问题的最小工作示例:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var subDateSchema = new Schema({
    date_add: {type: Date, default: Date.now},
    date_remove: {type: Date, default: null}
});

var ResourceSchema = new Schema({
    activation_dates: [subDateSchema]
});

subDateSchema.pre('remove', function(next){
    next(new Error("YOU CAN'T DELETE ANY ACTIVATION DATE"));
});

var Resource = mongoose.model('Resource', ResourceSchema);

var newresource = new Resource({
    activation_dates: [{
        date_add: Date.now()
    }]
});

newresource.save(function(err){
    if(err) throw err;
    newresource.activation_dates.splice(0, 1);
    /**
      * Here I tried
      * newresource.markModified('activation_dates');
      * On update it *DOES* trigger pre save and pre validate
      * But it does nothing to deleted content
    **/ 
    newresource.save(function(err){
        if(err) throw err;
    });
});

所以我的问题是:有没有一种干净的方法可以调用 sub doc 删除中间件,而无需继续检查所有以前的元素并与新元素进行比较以查看哪些元素被删除了?

经过一些研究,我发现了这个:

一种解决方法是将一个事件挂接到整个子文档数组,并复制之前的数据数组。

这是关于如何确保数组元素未被删除或拉出 的完整工作示例。要检查修改,您需要进一步修改。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var ResourceSchema = new Schema({
    activation_dates: [subDateSchema]
});

// This virtual permits to store the original array accross the middlewares
ResourceSchema.virtual("original").set(function(item){
    this._original = item;
}).get(function(){
    return this._original;
});

// This middleware checks for a previous version of the "Resource"
ResourceSchema.pre("validate", function(next){
    var self = this;
    mongoose.model("Resource").findById(this._id, function(err, doc){
        if(err) throw err;
        self.original = doc;
        next();
    });
});

// This validation block checks for any modification of the array of sub documents
ResourceSchema.path("activation_dates").validate(function(value){
    var j;
    if(this.original){
        // if the new array is smaller than the original, no need to go further
        if(this.original.activation_dates.length > value.length){
            return false;
        }

        for(var i=0; i < this.original.activation_dates.length; i++){
            j=0;
            // if the array element has been deleted but not pulled out, we need to check it
            if(typeof value[j] == "undefined" || typeof value[j]._id == "undefined"){
                return false;
            }

            while(value.length > j && this.original.activation_dates[i]._id.toString() != value[j]._id.toString()){
                j++;
            }
            if(j == value.length){
                return false;
            }
        }
    }
    return true;
}, "You deleted at least one element of the array");

var Resource = mongoose.model('Resource', ResourceSchema);

var newresource = new Resource({
    activation_dates: [{
        date_add: Date.now()
    }]
});

newresource.save(function(err){
    if(err) throw err;

    newresource.activation_dates.splice(0, 1);
    // OR:
    //delete newresource.activation_dates[0];
    // this line is essential in the case you *delete* but not pull out
    newresource.markModified('activation_dates');

    newresource.save(function(err){
        if(err) throw err;
    });
});

不幸的是,除了对所有元素进行循环并检索原始文档之外,我找不到其他解决方案。