高级专题

迁移框架

以下框架显示了一个典型的迁移文件.

  1. module.exports = {
  2. up: (queryInterface, Sequelize) => {
  3. // 转变为新状态的逻辑
  4. },
  5. down: (queryInterface, Sequelize) => {
  6. // 恢复更改的逻辑
  7. }
  8. }

我们可以使用 migration:generate 生成该文件. 这将在您的迁移文件夹中创建 xxx-migration-skeleton.js.

  1. $ npx sequelize-cli migration:generate --name migration-skeleton

传递的 queryInterface 对象可以用来修改数据库. Sequelize 对象存储可用的数据类型,如 STRINGINTEGER. 函数 updown 应该返回一个 Promise . 让我们来看一个例子

  1. module.exports = {
  2. up: (queryInterface, Sequelize) => {
  3. return queryInterface.createTable('Person', {
  4. name: Sequelize.STRING,
  5. isBetaMember: {
  6. type: Sequelize.BOOLEAN,
  7. defaultValue: false,
  8. allowNull: false
  9. }
  10. });
  11. },
  12. down: (queryInterface, Sequelize) => {
  13. return queryInterface.dropTable('Person');
  14. }
  15. }

以下是在数据库中执行两项更改的迁移示例,使用事务确保在发生故障时成功执行或回滚所有指令:

  1. module.exports = {
  2. up: (queryInterface, Sequelize) => {
  3. return queryInterface.sequelize.transaction((t) => {
  4. return Promise.all([
  5. queryInterface.addColumn('Person', 'petName', {
  6. type: Sequelize.STRING
  7. }, { transaction: t }),
  8. queryInterface.addColumn('Person', 'favoriteColor', {
  9. type: Sequelize.STRING,
  10. }, { transaction: t })
  11. ])
  12. })
  13. },
  14. down: (queryInterface, Sequelize) => {
  15. return queryInterface.sequelize.transaction((t) => {
  16. return Promise.all([
  17. queryInterface.removeColumn('Person', 'petName', { transaction: t }),
  18. queryInterface.removeColumn('Person', 'favoriteColor', { transaction: t })
  19. ])
  20. })
  21. }
  22. };

下一个是具有外键的迁移示例. 你可以使用 references 来指定外键:

  1. module.exports = {
  2. up: (queryInterface, Sequelize) => {
  3. return queryInterface.createTable('Person', {
  4. name: Sequelize.STRING,
  5. isBetaMember: {
  6. type: Sequelize.BOOLEAN,
  7. defaultValue: false,
  8. allowNull: false
  9. },
  10. userId: {
  11. type: Sequelize.INTEGER,
  12. references: {
  13. model: {
  14. tableName: 'users',
  15. schema: 'schema'
  16. }
  17. key: 'id'
  18. },
  19. allowNull: false
  20. },
  21. });
  22. },
  23. down: (queryInterface, Sequelize) => {
  24. return queryInterface.dropTable('Person');
  25. }
  26. }

下一个是使用 async/await 的迁移示例,你可以在其中为新列创建唯一索引:

  1. module.exports = {
  2. async up(queryInterface, Sequelize) {
  3. const transaction = await queryInterface.sequelize.transaction();
  4. try {
  5. await queryInterface.addColumn(
  6. 'Person',
  7. 'petName',
  8. {
  9. type: Sequelize.STRING,
  10. },
  11. { transaction }
  12. );
  13. await queryInterface.addIndex(
  14. 'Person',
  15. 'petName',
  16. {
  17. fields: 'petName',
  18. unique: true,
  19. },
  20. { transaction }
  21. );
  22. await transaction.commit();
  23. } catch (err) {
  24. await transaction.rollback();
  25. throw err;
  26. }
  27. },
  28. async down(queryInterface, Sequelize) {
  29. const transaction = await queryInterface.sequelize.transaction();
  30. try {
  31. await queryInterface.removeColumn('Person', 'petName', { transaction });
  32. await transaction.commit();
  33. } catch (err) {
  34. await transaction.rollback();
  35. throw err;
  36. }
  37. },
  38. };

.sequelizerc 文件

这是一个特殊的配置文件. 它允许你指定通常作为参数传递给CLI的各种选项:

  • env: 在其中运行命令的环境
  • config: 配置文件的路径
  • options-path: 带有其他参数的 JSON 文件的路径
  • migrations-path: migrations 文件夹的路径
  • seeders-path: seeders 文件夹的路径
  • models-path: models 文件夹的路径
  • url: 要使用的数据库连接字符串. 替代使用 —config 文件
  • debug: 可用时显示各种调试信息

在某些情况下,你可以使用它.

  • 你想要覆盖到 migrations, models, seedersconfig 文件夹的路径.
  • 你想要重命名 config.json 成为别的名字比如 database.json

还有更多的, 让我们看一下如何使用这个文件进行自定义配置.

对于初学者,让我们在项目的根目录中创建一个空文件.

  1. $ touch .sequelizerc

现在可以使用示例配置.

  1. const path = require('path');
  2. module.exports = {
  3. 'config': path.resolve('config', 'database.json'),
  4. 'models-path': path.resolve('db', 'models'),
  5. 'seeders-path': path.resolve('db', 'seeders'),
  6. 'migrations-path': path.resolve('db', 'migrations')
  7. }

通过这个配置你告诉CLI:

  • 使用 config/database.json 文件来配置设置
  • 使用 db/models 作为模型文件夹
  • 使用 db/seeders 作为种子文件夹
  • 使用 db/migrations 作为迁移文件夹

动态配置

配置文件是默认的一个名为 config.json 的JSON文件. 但有时你想执行一些代码或访问环境变量,这在JSON文件中是不可能的.

Sequelize CLI可以从“JSON”和“JS”文件中读取. 这可以用.sequelizerc文件设置. 让我们来看一下

首先,你需要在项目的根文件夹中创建一个 .sequelizerc 文件. 该文件应该覆盖 JS 文件的配置路径. 推荐这个

  1. const path = require('path');
  2. module.exports = {
  3. 'config': path.resolve('config', 'config.js')
  4. }

现在,Sequelize CLI将加载 config/config.js 以获取配置选项. 由于这是一个JS文件,你可以执行任何代码并导出最终的动态配置文件.

一个 config/config.js 文件的例子

  1. const fs = require('fs');
  2. module.exports = {
  3. development: {
  4. username: 'database_dev',
  5. password: 'database_dev',
  6. database: 'database_dev',
  7. host: '127.0.0.1',
  8. dialect: 'mysql'
  9. },
  10. test: {
  11. username: 'database_test',
  12. password: null,
  13. database: 'database_test',
  14. host: '127.0.0.1',
  15. dialect: 'mysql'
  16. },
  17. production: {
  18. username: process.env.DB_USERNAME,
  19. password: process.env.DB_PASSWORD,
  20. database: process.env.DB_NAME,
  21. host: process.env.DB_HOSTNAME,
  22. dialect: 'mysql',
  23. dialectOptions: {
  24. ssl: {
  25. ca: fs.readFileSync(__dirname + '/mysql-ca-master.crt')
  26. }
  27. }
  28. }
  29. };

使用 Babel

现在你知道如何使用 .sequelizerc 文件了. 现在让我们看看如何用这个文件来使用带有 sequelize-cli 设置的 babel. 这将允许你使用 ES6/ES7 语法编写 migration 和 seeder.

首先安装 babel-register

  1. $ npm i --save-dev babel-register

现在让我们创建 .sequelizerc 文件,它可以包含你可能想要为 sequelize-cli 更改的任何配置,但除此之外我们还希望它为我们的代码库注册 babel. 像这样

  1. $ touch .sequelizerc # Create rc file

现在这个文件中包含 babel-register 配置

  1. require("babel-register");
  2. const path = require('path');
  3. module.exports = {
  4. 'config': path.resolve('config', 'config.json'),
  5. 'models-path': path.resolve('models'),
  6. 'seeders-path': path.resolve('seeders'),
  7. 'migrations-path': path.resolve('migrations')
  8. }

现在 CLI 将能够从 migration/seeder 等运行 ES6/ES7 代码.请记住这取决于你的 .babelrc 配置.请在babeljs.io了解更多相关信息.

使用环境变量

使用CLI,你可以直接访问 config/config.js 内的环境变量. 你可以使用 .sequelizerc 来告诉CLI使用 config/config.js 进行配置. 这在上一节中有所解释.

然后你可以使用正确的环境变量来暴露文件.

  1. module.exports = {
  2. development: {
  3. username: 'database_dev',
  4. password: 'database_dev',
  5. database: 'database_dev',
  6. host: '127.0.0.1',
  7. dialect: 'mysql'
  8. },
  9. test: {
  10. username: process.env.CI_DB_USERNAME,
  11. password: process.env.CI_DB_PASSWORD,
  12. database: process.env.CI_DB_NAME,
  13. host: '127.0.0.1',
  14. dialect: 'mysql'
  15. },
  16. production: {
  17. username: process.env.PROD_DB_USERNAME,
  18. password: process.env.PROD_DB_PASSWORD,
  19. database: process.env.PROD_DB_NAME,
  20. host: process.env.PROD_DB_HOSTNAME,
  21. dialect: 'mysql'
  22. }
  23. };

指定方言选项

有时你想指定一个 dialectOption,如果它是一个通用配置,你可以将其添加到 config/config.json 中. 有时你想执行一些代码来获取 dialectOptions,你应该为这些情况使用动态配置文件.

  1. {
  2. "production": {
  3. "dialect":"mysql",
  4. "dialectOptions": {
  5. "bigNumberStrings": true
  6. }
  7. }
  8. }

生产用途

有关在生产环境中使用CLI和迁移设置的一些提示.

1) 使用环境变量进行配置设置. 这是通过动态配置更好地实现的. 样品生产安全配置可能看起来像

  1. const fs = require('fs');
  2. module.exports = {
  3. development: {
  4. username: 'database_dev',
  5. password: 'database_dev',
  6. database: 'database_dev',
  7. host: '127.0.0.1',
  8. dialect: 'mysql'
  9. },
  10. test: {
  11. username: 'database_test',
  12. password: null,
  13. database: 'database_test',
  14. host: '127.0.0.1',
  15. dialect: 'mysql'
  16. },
  17. production: {
  18. username: process.env.DB_USERNAME,
  19. password: process.env.DB_PASSWORD,
  20. database: process.env.DB_NAME,
  21. host: process.env.DB_HOSTNAME,
  22. dialect: 'mysql',
  23. dialectOptions: {
  24. ssl: {
  25. ca: fs.readFileSync(__dirname + '/mysql-ca-master.crt')
  26. }
  27. }
  28. }
  29. };

我们的目标是为各种数据库秘密使用环境变量,而不是意外检查它们来源控制.

存储

可以使用三种类型的存储:sequelize,jsonnone.

  • sequelize : 将迁移和种子存储在 sequelize 数据库的表中
  • json : 将迁移和种子存储在json文件上
  • none : 不存储任何迁移/种子

迁移存储

默认情况下,CLI 将在你的数据库中创建一个名为 SequelizeMeta 的表,其中包含每个执行迁移的条目. 要更改此行为,可以在配置文件中添加三个选项. 使用 migrationStorage 可以选择要用于迁移的存储类型. 如果选择 json,可以使用 migrationStoragePath 指定文件的路径,或者 CLI 将写入 sequelize-meta.json 文件. 如果要将数据保存在数据库中,请使用 sequelize,但是要使用其他表格,可以使用 migrationStorageTableName.你还可以通过提供migrationStorageTableSchema属性为SequelizeMeta表定义不同的 schema.

  1. {
  2. "development": {
  3. "username": "root",
  4. "password": null,
  5. "database": "database_development",
  6. "host": "127.0.0.1",
  7. "dialect": "mysql",
  8. // 使用不同的存储类型. Default: sequelize
  9. "migrationStorage": "json",
  10. // 使用不同的文件名. Default: sequelize-meta.json
  11. "migrationStoragePath": "sequelizeMeta.json",
  12. // 使用不同的表名. Default: SequelizeMeta
  13. "migrationStorageTableName": "sequelize_meta",
  14. // SequelizeMeta 表使用不同的 schema
  15. "migrationStorageTableSchema": "custom_schema"
  16. }
  17. }

注意: 不推荐使用 none 存储作为迁移存储. 如果你决定使用它,请注意将会没有任何移动记录或没有运行的记录.

种子储存

默认情况下,CLI 不会保存任何被执行的种子. 如果你选择更改此行为(!),则可以在配置文件中使用 seederStorage 来更改存储类型. 如果选择 json,可以使用 seederStoragePath 指定文件的路径,或者 CLI 将写入文件 sequelize-data.json. 如果要将数据保存在数据库中,请使用 sequelize,你可以使用 seederStorageTableName 指定表名,否则将默认为SequelizeData.

  1. {
  2. "development": {
  3. "username": "root",
  4. "password": null,
  5. "database": "database_development",
  6. "host": "127.0.0.1",
  7. "dialect": "mysql",
  8. // 使用不同的存储空间. Default: none
  9. "seederStorage": "json",
  10. // 使用不同的文件名. Default: sequelize-data.json
  11. "seederStoragePath": "sequelizeData.json",
  12. // 使用不同的表名 Default: SequelizeData
  13. "seederStorageTableName": "sequelize_data"
  14. }
  15. }

配置连接字符串

作为 --config 选项的替代方法,可以使用定义数据库的配置文件,你可以使用 --url 选项传递连接字符串. 例如:

  1. $ npx sequelize-cli db:migrate --url 'mysql://root:password@mysql_host.com/database_name'

传递方言特定参数

  1. {
  2. "production": {
  3. "dialect":"postgres",
  4. "dialectOptions": {
  5. // SSL 这样的方言参数
  6. }
  7. }
  8. }

程序化使用

Sequelize 有一个 [姊妹库][1],用于以编程方式处理迁移任务的执行和记录.