Sequelize.sync:当table不存在时创建索引
Sequelize.sync: Create indexes when table does not exist
根据 documentation sequelize.sync()
没有 {force: true}
或 {alter:true}
应该忽略已经存在的 table 和 create/sync 只有新的.但是至少有两个用例,现有 table 没有被完全忽略并且引入了错误。
我的设置:
sequelize.sync()
用作迁移前步骤以创建架构中不存在的 tables
sequelize.migrate()
用于改变任何现有的 tables。
注意:Sequelize 模型被视为反映数据库模式的单一真实来源。它们总是更新以反映数据库中存在的所有 indexes/fields。
重现步骤
步骤 1:创建具有两个字段 name
和 email
的 User
模型。 Email
有唯一索引
const users = sequelizeClient.define('users', {
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
indexes: [
{
unique: true,
fields: ['email'],
},
],
});
没有迁移,因此 table 预计将使用 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
到用户 table 并添加一个唯一索引。添加将更改 table 结构并创建索引的迁移。 sequelize.sync()
预计会忽略此 table 但永远不会执行迁移,因为 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'],
},
],
});
有人可以在这里提出解决方法,以便仅在 table 不存在时才会创建索引
另一个用例是当您添加带有评论的新字段时
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';
在生产环境中同步数据库的正确且非破坏性的方法是通过迁移。这样操作的顺序(新字段创建,索引创建等)得到保证。
所以一般来说,sync应该只用在开发和测试环境中。
引用自官方文档:
sync({ force: true }) and sync({ alter: true }) can be destructive operations. Therefore, they are not recommended for production-level software. Instead, synchronization should be done with the advanced concept of Migrations, with the help of the Sequelize CLI.
更多信息here(部分:“生产同步”)。
如果有人像我一样还在苦苦挣扎,因为续集更新等对上述答案不满意,这就是我解决问题的方法。
我正在使用 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"],
},
],
}
);
根据 documentation sequelize.sync()
没有 {force: true}
或 {alter:true}
应该忽略已经存在的 table 和 create/sync 只有新的.但是至少有两个用例,现有 table 没有被完全忽略并且引入了错误。
我的设置:
sequelize.sync()
用作迁移前步骤以创建架构中不存在的 tablessequelize.migrate()
用于改变任何现有的 tables。
注意:Sequelize 模型被视为反映数据库模式的单一真实来源。它们总是更新以反映数据库中存在的所有 indexes/fields。
重现步骤
步骤 1:创建具有两个字段 name
和 email
的 User
模型。 Email
有唯一索引
const users = sequelizeClient.define('users', {
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
indexes: [
{
unique: true,
fields: ['email'],
},
],
});
没有迁移,因此 table 预计将使用 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
到用户 table 并添加一个唯一索引。添加将更改 table 结构并创建索引的迁移。 sequelize.sync()
预计会忽略此 table 但永远不会执行迁移,因为 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'],
},
],
});
有人可以在这里提出解决方法,以便仅在 table 不存在时才会创建索引
另一个用例是当您添加带有评论的新字段时
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';
在生产环境中同步数据库的正确且非破坏性的方法是通过迁移。这样操作的顺序(新字段创建,索引创建等)得到保证。
所以一般来说,sync应该只用在开发和测试环境中。
引用自官方文档:
sync({ force: true }) and sync({ alter: true }) can be destructive operations. Therefore, they are not recommended for production-level software. Instead, synchronization should be done with the advanced concept of Migrations, with the help of the Sequelize CLI.
更多信息here(部分:“生产同步”)。
如果有人像我一样还在苦苦挣扎,因为续集更新等对上述答案不满意,这就是我解决问题的方法。
我正在使用 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"],
},
],
}
);