1

サブドキュメントが削除されないようにするため、各サブドキュメントスキーマの pre('remove') ミドルウェアにエラーを追加しました。

.remove() 関数を呼び出すと、効果的にミドルウェアが呼び出されます。ただし、remove() を呼び出さずに削除すると、ミドルウェアは削除されたかどうかを確認しません。

問題になるのは、リモート ソースからオブジェクトを受け取るときです。マングース ミドルウェアを介してすべての整合性チェックを実行し、すべてを同じ場所に保持したいと考えています。リモート ソースは、間違っているかどうかにかかわらず、サブ ドキュメントの 1 つを削除している可能性があります。そのため、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 に答える