少し調べてみたところ、次のことがわかりました。
回避策は、サブドキュメントの配列全体にイベントをフックし、前のデータの配列のコピーを作成することです。
これは、配列要素が削除または削除されていないことを確認する方法に関する完全な実例です。 。変更を確認するには、さらに変更が必要です。
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;
});
});
残念ながら、すべての要素をループして元のドキュメントを取得する以外に、別の解決策を見つけることができませんでした。