Предоставляет ли Mongoose доступ к предыдущему значению свойства в pre ('save')?

Я хотел бы сравнить новое/входящее значение свойства с предыдущим значением этого свойства (то, что в настоящее время сохраняется в db) в рамках промежуточного программного обеспечения pre('save').

Предоставляет ли Mongoose средство для этого?

Ответы

Ответ 1

Mongoose позволяет вам настраивать настраиваемые устройства, в которых вы выполняете сравнение. pre ('save') сам по себе не даст вам то, что вам нужно, но вместе:

schema.path('name').set(function (newVal) {
  var originalVal = this.name;
  if (someThing) {
    this._customState = true;
  }
});
schema.pre('save', function (next) {
  if (this._customState) {
    ...
  }
  next();
})

Ответ 2

Принятый ответ работает очень хорошо. Также можно использовать альтернативный синтаксис, в котором установщик встроен с определением схемы:

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

Ответ 3

Честно говоря, я попробовал решения, размещенные здесь, но мне пришлось создать функцию, которая хранит старые значения в массиве, сохраняет значения, а затем видит разницу.

// 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
    }
}

Ответ 4

Я искал решение для обнаружения изменений в любом из нескольких полей. Поскольку похоже, что вы не можете создать установщик для полной схемы, я использовал виртуальное свойство. Я обновляю записи только в нескольких местах, так что это довольно эффективное решение для такой ситуации:

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) {

}