【问题标题】:Does Mongoose provide access to previous value of property in pre('save')?Mongoose 是否提供对 pre('save') 中属性先前值的访问?
【发布时间】:2012-07-11 06:32:50
【问题描述】:

我想在pre('save') 中间件中将属性的新值/传入值与该属性的先前值(当前保存在数据库中的值)进行比较。

Mongoose 是否提供了执行此操作的工具?

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    我一直在寻找一种解决方案来检测多个字段中任何一个字段的变化。由于看起来您无法为完整架构创建设置器,因此我使用了虚拟属性。我只更新了几个地方的记录,所以对于这种情况,这是一个相当有效的解决方案:

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

    假设您的 Person 移动了,您需要更新他的地址:

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

    然后在您的 pre 钩子中,您只需要引用 _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) {
    
    }
    

    【讨论】:

      【解决方案2】:

      老实说,我尝试了此处发布的解决方案,但我必须创建一个函数,将旧值存储在数组中,保存值,然后查看差异。

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

      【讨论】:

      • 这不使用中间件,所以它不是对所提问题的回答
      【解决方案3】:

      接受的答案效果很好。也可以使用另一种语法,将 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();
      });
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 我是否需要这样做才能访问 validators 中的先前值?或者在验证器的情况下有更直接的方法?
        • @aaronheckmann 很抱歉恢复了一个旧线程,我想这不会起作用,如果我们在负载均衡器后面有多个节点服务器。
        • @aaronheckmann 如果您使用的是 nginx,则有一个值可以指定主机,并将其发送到之前发送的同一服务器..或者您是如何解决的?
        • 我不知道这是否曾经有效,但它不再有效。 this.name 未定义
        • 我知道你写这篇 @JoshWoodcock 已经 4 年了,但我遇到了同样的问题。
        猜你喜欢
        • 2019-07-26
        • 2013-07-15
        • 2021-01-08
        • 2015-07-20
        • 2018-04-22
        • 2014-03-22
        • 1970-01-01
        • 2018-11-17
        • 2016-07-22
        相关资源
        最近更新 更多