了解 Sequelize 数据库迁移和种子
Posted
技术标签:
【中文标题】了解 Sequelize 数据库迁移和种子【英文标题】:Understanding Sequelize database migrations and seeds 【发布时间】:2018-05-28 21:24:30 【问题描述】:我正试图深入了解 Sequelize 的迁移以及它们如何与种子(或者一般的迁移和种子)一起工作。 我设置了一切以使迁移正常工作。
首先,让我们创建一个users
表:
// migrations/01-create-users.js
module.exports =
up: (queryInterface, Sequelize) =>
return queryInterface.createTable("Users",
id:
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
,
email:
type: Sequelize.STRING
,
createdAt:
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
,
updatedAt:
type: Sequelize.DATE
);
,
down: (queryInterface, Sequelize) =>
return queryInterface.dropTable("Users");
;
很好。如果我想播种(管理员)用户,我可以这样做:
// seeders/01-demo-user.js
module.exports =
up: (queryInterface, Sequelize) =>
return queryInterface.bulkInsert(
"Users",
[
email: "demo@demo.com"
],
);
,
down: (queryInterface, Sequelize) =>
return queryInterface.bulkDelete("Users", null, );
;
然后为了让魔法发生,我会这样做:
$ sequelize db:migrate
这会在数据库中创建users
表。运行迁移后,下一步是播种,因此:
$ sequelize db:seed:all
Tataa,现在我在 users
数据库中有一个用户。太好了。
但现在我想将firstname
添加到users
表中,所以我必须添加另一个迁移:
// migrations/02-alter-users.js
module.exports =
up: (queryInterface, Sequelize) =>
return queryInterface.addColumn("Users", "firstname",
type: Sequelize.STRING
);
,
down: (queryInterface, Sequelize) =>
return queryInterface.removeColumn("Users", "firstname");
;
再次运行迁移只会运行第二个迁移,因为它保存在第一个已执行的数据库中。但默认情况下,sequelize 会重新运行所有播种机。那么我应该调整seeders/01-demo-user.js
还是更改默认行为并将播种机存储在数据库中并创建一个仅更新firstname
的新播种机?
如果firstname
不能是null
,那么先运行迁移然后旧版本的seeders/01-demo-user.js
会抛出错误,因为firstname
不能是null
。
重新运行播种器会导致另一个问题:已经有一个用户使用demo@demo.com
电子邮件。第二次运行它会复制用户。还是我必须在播种机中检查类似的东西?
以前,我只是在迁移中添加了用户帐户,因此我可以确定何时将其添加到数据库以及何时必须更新它。但是有人告诉我我做错了,我必须使用播种机来完成这样的任务。
非常感谢任何帮助/见解。
【问题讨论】:
你能解决这个问题吗?我也有同样的问题。 并非如此。现在,如果我正在使用播种机,我也将它们存储在运行它们的数据库中,这样它们就不会再次运行。 【参考方案1】:在我看来,播种机是一种只运行一次的东西,而迁移是你不断地逐层添加到数据库结构中的东西。
我会使用播种器来填充一些查找或其他很可能不会更改的数据,或测试数据。在sequelize
docs 中说,“种子文件是数据中的一些更改,可用于使用示例数据或测试数据填充数据库表。”
如果您想在数据结构已更改时进行一些动态数据更新,您可以在需要时直接在迁移中运行原始查询。因此,例如,如果您在 up
方法中添加了一些列,您可以根据您的业务逻辑更新数据库中的行,例如:
// Add column, allow null at first
await queryInterface.addColumn("users", "user_type",
type: Sequelize.STRING,
allowNull: true
);
// Update data
await queryInterface.sequelize.query("UPDATE users SET user_type = 'simple_user' WHERE is_deleted = 0;");
// Change column, disallow null
await queryInterface.changeColumn("users", "user_type",
type: Sequelize.STRING,
allowNull: false
);
在 Google 网上论坛中也有一个有趣的discussion 关于这个主题。希望对你有帮助。
【讨论】:
这应该是公认的答案。只是遇到了同样的困惑。完美地说。谢谢 The Sequelize docs 在声明中混淆了这个问题:“要管理所有数据迁移,您可以使用播种机”。这根本不是真的。有很多原因应该更新迁移文件中的数据,而不是种子。在已建立的应用程序中,迁移文件中的数据更新似乎比播种机更频繁。 如果我编写一些迁移和播种器,它依赖于这些迁移然后添加更多迁移,使播种器对新列无效,我有点困惑......当然,我可以更新新迁移中的数据,但是如果我想创建一个新的数据库会发生什么?新的迁移依赖于首先运行的播种机......我认为真正应该发生的是迁移和播种机的特定顺序。【参考方案2】:根据我的经验,迁移会改变结构。播种机...种子数据。最近我在一个没有配置播种机的项目上。 https://sequelize.org/master/manual/migrations.html#seed-storage。这将允许您设置一个文件,这样您的数据就不会被多次播种。迁移配置也在那里。
【讨论】:
【参考方案3】:您好,试试 bulkUpdate...
'use strict';
module.exports =
up: (queryInterface, Sequelize) => queryInterface.addColumn(
'Users',
'user_type',
type: Sequelize.STRING,
allowNull: false,
).then(()=>
queryInterface.bulkUpdate('Users',
user_type: 'simple_user',
,
is_deleted : 0,
)
),
down: (queryInterface, Sequelize) =>
queryInterface.removeColumn('Users', 'user_type')
;
【讨论】:
以上是关于了解 Sequelize 数据库迁移和种子的主要内容,如果未能解决你的问题,请参考以下文章