1

我会阻止任何子文档被删除,因此我在每个子文档模式的 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;
    });
});

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

4

1 回答 1

1

经过一番研究,我发现了这一点:

一种解决方法是将事件挂钩到整个子文档数组,并拥有前一个数据数组的副本。

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

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

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

于 2015-08-15T15:56:21.273 回答