【问题标题】:Sequelize JSON data type序列化 JSON 数据类型
【发布时间】:2017-05-07 22:18:29
【问题描述】:

我已将模型定义为

module.exports = function (sequelize, DataTypes) {
  const MyModel = sequelize.define('MyModel', {
    data: {
      type: DataTypes.JSON,
      ...
    },
    ...
  });

  return MyModel;
};

我使用查询它

MyModel.findAll().then(myModels => ...);

但是,查询结果中的data 字段是字符串,而不是 JSON 对象。我该如何解决?

【问题讨论】:

  • 使用JSON.parse(data)
  • @AkshayKumar 这不是我认为应该要求的。如果字段类型已经是 JSON,它应该返回 JSON 而不是字符串。
  • @MikkoP 你用的是哪个数据库?
  • @divsingh MySQL 在标签中,所以我猜是 MySQL
  • 在 postgres 中按预期工作。

标签: mysql json node.js sequelize.js


【解决方案1】:

虽然这个问题被标记为 MySQL,但我怀疑一些使用 MariaDB 的人可能最终还是会在这里结束,尤其是因为 MariaDB 现在在许多地方都是默认设置。 MySQL 和 MariaDB 处理 JSON 数据类型的方式有所不同,这就是为什么 sequelize 对这两个 DB 的实现方式不同。

就我而言,我通过将续集显式切换为方言mariadb 来解决此问题。这需要您安装mariadb 包而不是mysql2。之后我的 JSON 列被正确解析为一个对象。

【讨论】:

  • 到底发生了什么事
【解决方案2】:

无需使用 getter 和 setter,因为 sequelize 现在支持 JSON。请参阅 sequelize api

【讨论】:

  • 和你一起登顶!
  • 这不是很清楚。您链接到 OP 已经在使用的 DataTypes.JSON 的文档。
【解决方案3】:

最简单的解决方案是使用这个名为sequelize-json的小库

创建数据库和架构:

var Sequelize = require('sequelize'),
  JsonField = require('sequelize-json'),
  db,
  User;

db = new Sequelize('database', 'username', 'password', {
  dialect: 'sqlite',
  logging: false
});

User = db.define('User', {
  username: Sequelize.STRING,
  jsonField: JsonField(db, 'User', 'jsonField')
});

注意 JsonField 的参数,传递你的 Sequelize 实例、模型名称和字段名称。有点尴尬,但这是为模型实例添加适当的钩子所必需的。

现在,您始终可以将该字段视为 json 对象:

User.create({
      username: 'Scott',
      jsonField: {
        likes: ['running', 'node']
      }
    })
    .then(function(user) {
      user.jsonField.likes.push('tests');
      return user.save();
    })
    .then(function(user) {
      expect(user.jsonField).to.be.a('object');
      expect(user.jsonField.likes).to.have.length(3);
    });
它将与普通的保存命令以及 updateAttribute 命令一起使用。

【讨论】:

    【解决方案4】:

    Jalal 的回答很棒,但除非我稍微调整一下,否则对我不起作用。这对我有用:

    首先:创建一个迁移,将您想要的字段添加为类型TEXT。 示例 - 我想在 Stores 表中添加一个名为 address 的字段:

    module.exports = {
      up: (queryInterface, Sequelize) => {
        return queryInterface.addColumn("Stores", "address", Sequelize.TEXT);
      },
    
      down: (queryInterface, Sequelize) => {
        return queryInterface.removeColumn("Stores", "address");
      }
    };
    

    下一步: 在您的模型中,将带有 getter 和 setter 的字段添加到您的字段和数据类型列表(对象)中:

    address: {
      type: DataTypes.TEXT,
        get: function() {
          return JSON.parse(this.getDataValue("address"));
        },
        set: function(value) {
          return this.setDataValue("address", JSON.stringify(value));
        }
    },
    

    所以我的整个模型看起来像这样:

    module.exports = (sequelize, DataTypes) => {
      const Store = sequelize.define(
        "Store",
        {
          name: DataTypes.STRING,
          isActive: DataTypes.BOOLEAN,
          address: {
            type: DataTypes.TEXT,
            get: function() {
              return JSON.parse(this.getDataValue("address"));
            },
            set: function(value) {
              return this.setDataValue("address", JSON.stringify(value));
            }
          }
        },
        {}
      );
      Store.associate = function(models) {
        // associations can be defined here
        Store.hasMany(models.Order, {
          foreignKey: "id",
          targetKey: "storeId"
        });
      };
      return Store;
    };
    

    现在您可以像在数据库中使用 JSON 类型字段一样创建和检索记录。

    例如:const store = await Store.create({name: "Joe's corner store", address: {address1: "123 test street", city: "Los Angeles", state: "CA"}})

    一些注意事项:

    在上面的代码块中...

    • address 替换为您要使用的字段名称。
    • Stores 替换为您的模型/表名称。
    • 我在设置器上添加了return,否则在尝试创建新记录时会出错(Jalal 的方式)。

    【讨论】:

      【解决方案5】:

      尚不支持MySQL JSON Data Type #4727。但你可以这样做:

       module.exports = function (sequelize, DataTypes) {
            const MyModel = sequelize.define('MyModel', {
              data: {
                type: Sequelize.TEXT,
                 get: function () {
                      return JSON.parse(this.getDataValue('value'));
                  },
                  set: function (value) {
                      this.setDataValue('value', JSON.stringify(value));
                  },
          ,
                ...
              },
              ...
            });
      
            return MyModel;
      };
      

      我还在 github sequelize-json 上找到了这个包,如果你不想使用 getter 和 setter,可以尝试一下。

      【讨论】:

      • 这应该是公认的答案,这非常完美谢谢 Jalal,另外 sequelize-json 模块是不需要的,它在 3-4 年内也没有得到支持,这适用于一切。需要注意的一点是 this.getDataValue('value'), value 应该是 'data',或者你的字段名称是什么。
      • 显然在 4.18 版本中添加了 JSON 支持以进行续集github.com/sequelize/sequelize/pull/7106#issuecomment-339549850
      • 请记住,MySQL 会将值截断为列的最大长度而没有错误,这意味着存储的 JSON 可能会被破坏(触发解析错误)。 set() 函数应该在保存之前验证长度。
      【解决方案6】:

      MySQL 不支持 JSON 数据类型。

      在此处查看文档http://docs.sequelizejs.com/en/v3/docs/models-definition/#data-types

      一种解决方法是在查询时使用文本和字符串化/解析

      【讨论】:

      • 自 Sequelize 4.18 起支持 MySQL 的 JSON
      猜你喜欢
      • 1970-01-01
      • 2016-04-07
      • 2023-03-31
      • 2021-06-14
      • 2017-02-05
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2018-08-01
      相关资源
      最近更新 更多