【问题标题】:Sequelize.sync: Create indexes when table does not existSequelize.sync:当表不存在时创建索引
【发布时间】:2021-04-14 21:28:21
【问题描述】:

根据documentation sequelize.sync() 没有{force: true}{alter:true} 应该忽略已经存在的表并只创建/同步新表。但是至少有两个用例是现有表没有被完全忽略并且引入了错误。

我的设置:

  1. sequelize.sync() 用作迁移前步骤以创建架构中不存在的表
  2. sequelize.migrate() 用于更改任何现有表。

注意:Sequelize 模型被视为反映数据库模式的单一事实来源。它们总是会更新以反映数据库中存在的所有索引/字段。

复制步骤

第 1 步:创建 User 模型,其中包含两个字段 nameemailEmail 具有唯一索引

const users = sequelizeClient.define('users', {
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  }, {
    indexes: [
      {
        unique: true,
        fields: ['email'],
      },
    ],
  });

没有迁移,因此预计将使用sequelize.sync() 创建表。 一切都按预期工作。这是生成的 SQL 脚本。

Executing (default): CREATE TABLE IF NOT EXISTS "users" ("id"  SERIAL , "name" VARCHAR(255) NOT NULL, "email" VARCHAR(255) NOT NULL, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): CREATE UNIQUE INDEX "users_email" ON "users" ("email")

第 2 步 将新字段 phonenumber 添加到用户表并添加唯一索引。添加将更改表结构并创建索引的迁移。 sequelize.sync() 预计会忽略此表,但永远不会执行迁移,因为 sequelize.sync() 会引发以下错误。


Executing (default): CREATE TABLE IF NOT EXISTS "users" ("id"  SERIAL , "name" VARCHAR(255) NOT NULL, "email" VARCHAR(255) NOT NULL, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): CREATE UNIQUE INDEX "users_phonenumber" ON "users" ("phonenumber")
{"_bitField":18087936,"_fulfillmentHandler0":{"name":"SequelizeDatabaseError","parent":{"name":"error","length":101,"severity":"ERROR","code":"42703","file":"indexcmds.c","line":"1083","routine":"ComputeIndexAttrs","sql":"CREATE UNIQUE INDEX \"users_phonenumber\" ON \"users\" (\"phonenumber\")"},"original":{"name":"error","length":101,"severity":"ERROR","code":"42703","file":"indexcmds.c","line":"1083","routine":"ComputeIndexAttrs","sql":"CREATE UNIQUE INDEX \"users_phonenumber\" ON \"users\" (\"phonenumber\")"},"sql":"CREATE UNIQUE INDEX \"users_phonenumber\" ON \"users\" (\"phonenumber\")"},"_trace":{"_promisesCreated":0,"_length":1},"level":"error","message":"Unhandled Rejection at: Promise "}

这是最终模型

const users = sequelizeClient.define('users', {
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    phoneNumber: { // new field
      type: DataTypes.STRING,
      allowNull: false,
    },

  }, {
    indexes: [
      {
        unique: true,
        fields: ['email'],
      },
      { // new index
        unique: true,
        fields: ['phoneNumber'],
      },
    ],
  });

有人可以在这里建议一个解决方法,这样只有在表不存在时才会创建索引


另一个用例是当您添加带有评论的新字段时

    fieldWithComment: {
      type: DataTypes.STRING,
      comment: 'my comment goes here',
    },

生成的 SQL 显然会引发错误,因为新列尚不存在。

CREATE TABLE IF NOT EXISTS "users" (
    "id"   SERIAL, 
    "name" VARCHAR(255) NOT NULL, 
    "email" VARCHAR(255) NOT NULL, 
    "phonenumber" VARCHAR(255) NOT NULL, 
    "fieldWithComment" VARCHAR(255) , PRIMARY KEY ("id")); 
        COMMENT ON COLUMN "users"."fieldWithComment" IS 'my comment goes here';

【问题讨论】:

    标签: node.js postgresql orm sequelize.js


    【解决方案1】:

    如果有人像我一样因为续集更新等原因仍在苦苦挣扎,对上述答案不满意,这就是我解决问题的方法。

    我使用的是underscore:true 选项。
    所以,我将fields: ["phone", "countryCode"], 改为fields: ["phone", "country_code"],

    sequelize.define(
      "user",
      {
        phone: {
          type: DataTypes.STRING(20),
          allowNull: false,
        },
        countryCode: {
          type: DataTypes.STRING(4),
          allowNull: false,
        },
        // other attributes ...
      },
      {
        freezeTableName: true,
        timestamps: true,
        underscored: true,
        indexes: [
          {
            unique: true,
            fields: ["phone", "country_code"],
          },
        ],
      }
    );
    
    

    【讨论】:

      【解决方案2】:

      在生产环境中同步数据库的正确且非破坏性的方法是通过迁移。这样可以确保操作的顺序(新字段创建、索引创建等)。

      因此,一般来说,同步应该只在开发和测试环境中使用。

      引用官方文档:

      sync({ force: true }) 和 sync({ alter: true }) 可能是破坏性操作。因此,不建议将它们用于生产级软件。相反,应该在 Sequelize CLI 的帮助下,使用迁移的高级概念来完成同步。

      更多信息here(部分:“生产中的同步”)。

      【讨论】:

      • 我认为这个答案不应该被接受,它只是说“不要同步,迁移”,但我想在测试环境中同步。
      猜你喜欢
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 2020-06-02
      • 2016-05-27
      • 2011-09-03
      • 2010-09-30
      • 1970-01-01
      • 2011-03-18
      相关资源
      最近更新 更多