sequelize: postgres .save() not able to detect change in JSON fields

When changing the dao, suppose the dao has a json field called “data”:

return dao.data // {"a": "b"}

After adding attributes to the dao:

dao.data.c = "d";
return dao.data // {"a": "b", "c": "d"}

Calling .save() on the dao will not save the new “c” attribute.

Looking into: https://github.com/sequelize/sequelize/blob/master/lib/instance.js#L377

Instance.prototype.changed = function(key) {
    if (key) {
        if (this.Model._isDateAttribute(key) && this._previousDataValues[key] && this.dataValues[key]) {
            return this._previousDataValues[key].valueOf() !== this.dataValues[key].valueOf();
        }
        return this._previousDataValues[key] !== this.dataValues[key];  // <-- this returns false because the internals of the json isn't compared.
    }
    var changed = Object.keys(this.dataValues).filter(function(key) {
        return this.changed(key);
    }.bind(this));

    return changed.length ? changed : false;
};

Nonetheless, one possible way is to compare the JSONs:

_isJSONAttribute = function(key) {
  return typeof key === "object";
}


Instance.prototype.changed = function(key) {
    if (key) {
        if (this.Model._isDateAttribute(key) && this._previousDataValues[key] && this.dataValues[key]) {
            return this._previousDataValues[key].valueOf() !== this.dataValues[key].valueOf();
        }
        //stringify and compare
        if (this.Model._isJSONAttribute(key) && this._previousDataValues[key] && this.dataValues[key]) {
            return JSON.stringify(this._previousDataValues[key]) !== JSON.stringify(this.dataValues[key]);
        }
        return this._previousDataValues[key] !== this.dataValues[key];
    }
    var changed = Object.keys(this.dataValues).filter(function(key) {
        return this.changed(key);
    }.bind(this));

    return changed.length ? changed : false;
};

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 38 (33 by maintainers)

Most upvoted comments

Whats the way to amend JSON fields?

Looking through the code I believe this works:

instance.setDataValue('json_field', { foo: 'bar' });

But i’m not entirely sure how you would set a nested field. Currently I’m doing this:

instance.json_field.foo = 'barbar';
instance.changed('json_field', true);

@BridgeAR @mickhansen

@curiousdannii Documentation PRs are very welcome 😃