Does Mongoose provide access to previous value of property in pre('save')?

前端 未结 4 720
南笙
南笙 2020-12-14 08:23

I\'d like to compare the new/incoming value of a property with the previous value of that property (what is currently saved in the db) within a pre(\'save\') mi

相关标签:
4条回答
  • 2020-12-14 08:48

    I was looking for a solution to detect changes in any one of multiple fields. Since it looks like you can't create a setter for the full schema, I used a virtual property. I'm only updating records in a few places so this is a fairly efficient solution for that kind of situation:

    Person.virtual('previousDoc').get(function() {
      return this._previousDoc;
    }).set(function(value) {
        this._previousDoc = value;
    });
    

    Let's say your Person moves and you need to update his address:

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

    Then in your pre hooks, you would just need to reference properties of _previousDoc such as:

    // 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) {
    
    }
    
    0 讨论(0)
  • 2020-12-14 08:53

    Honestly, I tried the solutions posted here, but I had to create a function that would store the old values in an array, save the values, and then see the difference.

    // 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
        }
    }
    
    0 讨论(0)
  • 2020-12-14 08:55

    The accepted answer works very nicely. An alternative syntax can also be used, with the setter inline with the Schema definition:

    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();
    });
    
    0 讨论(0)
  • 2020-12-14 08:57

    Mongoose allows you to configure custom setters in which you do the comparison. pre('save') by itself won't give you what you need, but together:

    schema.path('name').set(function (newVal) {
      var originalVal = this.name;
      if (someThing) {
        this._customState = true;
      }
    });
    schema.pre('save', function (next) {
      if (this._customState) {
        ...
      }
      next();
    })
    
    0 讨论(0)
提交回复
热议问题