猫鼬子文档预删除中间件未调用 [英] Mongoose sub document pre remove middleware not called

查看:123
本文介绍了猫鼬子文档预删除中间件未调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将防止删除任何子文档,因此在每个子文档Schema的pre('remove')中间件中添加了一个错误.

I would prevent any sub document from being removed, thus I added an error to the pre('remove') middleware of each sub document Schema.

当调用.remove()函数时,它有效地调用了中间件.但是,如果在不调用remove()的情况下将其删除,则中间件不会检查是否已将其删除.

When calling the .remove() function, it effectively calls the middleware. But when it is deleted without calling remove(), the middleware doesn't check if it has been removed.

最重要的情况是,当我从远程来源收到对象时,我想通过猫鼬中间件执行所有完整性检查,以将所有内容保存在同一位置.远程源可以删除或删除子文档之一.因此,当Mongoose检查整个文档时,子文档已被删除而没有触发.remove()函数.

The cases where is matters is when I receive an object from a remote source, I'd like to perform all the integrity checks via mongoose middlewares to keep everything at the same place. The remote source can have, by mistake or not, deleted one of the sub docs. So when Mongoose is checking the whole doc, the sub doc has already been removed without triggering the .remove() function.

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

Here is the minimal working example of my problem:

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

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

So my question is: Is there a clean way to call sub doc removing middleware without proceeding to check for all the previous elements and compare with the new ones to see which ones are being deleted ?

推荐答案

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

After a little bit of researches, I found this:

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

A workaround can be to hook an event to the whole array of Sub Documents, and to have a copy of the previous array of data.

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

This is a complete working example on how to be sure an array element hasn't been deleted or pulled out. To check for modifications, you'll need further modifications.

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

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

Unfortunately I couldn't find another solution than doing a loop over all elements and retrieving the original document.

这篇关于猫鼬子文档预删除中间件未调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆