我想在pre('save')
中间件中比较一个属性的新值/传入值与该属性的前一个值(当前保存在数据库中的值)。
Mongoose提供了这样做的工具吗?
接受的答案非常有效。也可以使用另一种语法,setter与Schema定义内联:
var Person = new mongoose.Schema({
name: {
type: String,
set: function(name) {
this._previousName = this.name;
return name;
}
});
Person.pre('save', function (next) {
var previousName = this._previousName;
if(someCondition) {
...
}
next();
});
Mongoose允许您配置用于进行比较的自定义setter。pre("ve")本身不会给你所需要的,但一起:
schema.path('name').set(function (newVal) {
var originalVal = this.name;
if (someThing) {
this._customState = true;
}
});
schema.pre('save', function (next) {
if (this._customState) {
...
}
next();
})
我正在寻找一种解决方案来检测多个字段中任何一个字段的更改。由于看起来无法为整个模式创建setter,所以我使用了一个虚拟属性。我只更新了少数地方的记录,所以这是一个相当有效的解决方案:
Person.virtual('previousDoc').get(function() {
return this._previousDoc;
}).set(function(value) {
this._previousDoc = value;
});
假设你的人移动了,你需要更新他的地址:
const person = await Person.findOne({firstName: "John", lastName: "Doe"});
person.previousDoc = person.toObject(); // create a deep copy of the previous doc
person.address = "123 Stack Road";
person.city = "Overflow";
person.state = "CA";
person.save();
然后在预挂钩中,您只需要引用_previousDoc的属性,例如:
// fallback to empty object in case you don't always want to check the previous state
const previous = this._previousDoc || {};
if (this.address !== previous.address) {
// do something
}
// you could also assign custom properties to _previousDoc that are not in your schema to allow further customization
if (previous.userAddressChange) {
} else if (previous.adminAddressChange) {
}
老实说,我尝试了这里发布的解决方案,但我必须创建一个函数,将旧值存储在数组中,保存值,然后查看差异。
// Stores all of the old values of the instance into oldValues
const oldValues = {};
for (let key of Object.keys(input)) {
if (self[key] != undefined) {
oldValues[key] = self[key].toString();
}
// Saves the input values to the instance
self[key] = input[key];
}
yield self.save();
for (let key of Object.keys(newValues)) {
if (oldValues[key] != newValues[key]) {
// Do what you need to do
}
}
我所做的是在预保存路由中使用this.cstructor来访问数据库中的当前值。
const oldData = this.constructor.findById(this.id)
然后,您可以从旧数据中获取您想要使用的特定密钥:)
let name = oldData.name
注意,这对字符串等简单数据很有效,但我发现它对子模式不太有效,因为mongoose内置了首先运行的功能。因此,有时您的oldData会与子模式的newData相匹配。这可以通过给它自己的预保存路线来解决!