【问题标题】:How to auto generate migrations with Sequelize CLI from Sequelize models?如何使用 Sequelize CLI 从 Sequelize 模型自动生成迁移?
【发布时间】:2015-03-06 07:29:53
【问题描述】:

我有一组 Sequelize 模型。我想使用迁移,而不是 DB Sync。

Sequelize CLI 似乎可以做到这一点,根据this article: "当您使用 CLI 生成模型时,您还将免费获得迁移脚本。"

如何使用 Sequelize CLI 从现有的 Sequelize 模型自动生成迁移?

【问题讨论】:

标签: mysql node.js orm sequelize.js


【解决方案1】:

如果您不想从头开始重新创建模型,可以使用以下 CLI 命令手动生成迁移文件:

sequelize migration:generate --name [name_of_your_migration]

这将生成一个空白的骨架迁移文件。虽然它不会将您的模型结构复制到文件中,但我确实发现它比重新生成所有内容更容易和更清洁。注意:确保从迁移目录的包含目录运行命令;否则 CLI 将为您生成一个新的迁移目录

【讨论】:

  • 这一点从未被提及,但在进行迁移以添加或删除列时需要,特别是如果您希望稍后更新生产环境。
  • 您可以从项目的根目录运行npx sequelize-cli migration:generate --name [name_of_your_migration]。但在你这样做之前,你需要告诉 sequelize-cli 在哪里生成你的迁移,sequelize-cli 为此使用名为 migrations-path 的配置。 sequelize.org/master/manual/…
  • 这根本没有回答问题。它只是生成一个骨架,里面没有数据,这就是 OP 所要求的
  • 谢谢,这真的很有用。无论如何,如果我们能按照 OP 的要求去做,那就太好了。
【解决方案2】:

您不能为现有模型创建迁移脚本。

资源:

如果采用经典方式,则必须通过 CLI 重新创建模型:

sequelize model:create --name MyUser --attributes first_name:string,last_name:string,bio:text

它将生成这些文件:

models/myuser.js:

"use strict";
module.exports = function(sequelize, DataTypes) {
  var MyUser = sequelize.define("MyUser", {
    first_name: DataTypes.STRING,
    last_name: DataTypes.STRING,
    bio: DataTypes.TEXT
  }, {
    classMethods: {
      associate: function(models) {
        // associations can be defined here
      }
    }
  });
  return MyUser;
};

迁移/20150210104840-create-my-user.js:

"use strict";
module.exports = {
  up: function(migration, DataTypes, done) {
    migration.createTable("MyUsers", {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER
      },
      first_name: {
        type: DataTypes.STRING
      },
      last_name: {
        type: DataTypes.STRING
      },
      bio: {
        type: DataTypes.TEXT
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE
      },
      updatedAt: {
        allowNull: false,
        type: DataTypes.DATE
      }
    }).done(done);
  },
  down: function(migration, DataTypes, done) {
    migration.dropTable("MyUsers").done(done);
  }
};

【讨论】:

  • 谢谢@Dor 我对使用 sequelize 的同步功能有一些疑问。据我了解,sequelize-cli 在内部使用 Umzug 进行所有迁移。您展示的示例确实帮助我入门,但是 Alter Table 的过程是什么,假设我想在 sequelize 中更改 MyUser 模型并让 sequelize cli 为我创建迁移脚本,sequelize cli 如何通过以下方式创建迁移脚本完成所有模型更改。
  • 通常你需要在同步能力之间进行分离,这对新数据库或演示很有用,在迁移之间。如果您有一个不断升级的生产系统并且不想丢失数据,那么迁移可能是您唯一的选择。不幸的是,CLI 仅适用于创建基本模板,它不运行特殊逻辑,也不扫描您的模型。 (我也对此感到失望。)您需要创建迁移来转换架构/数据,并且您需要将模型更改为表示最新的架构,就好像它一直都是这样。
  • 感谢@Dor,但为更改编写迁移脚本似乎需要做很多工作。我希望以某种方式可以避免迁移脚本,并且默认情况下可以发生同步。
  • 而您链接到的视频确实显示他能够从现有模型创建迁移(查看他在 5:40 后键入 stukko addMigration 的时间)。跨度>
  • 感谢@DorRotman - 我真的希望“您负责维护迁移文件和模型文件之间的一致性”在续集文档中得到明确解决,因为这是一个巨大的细节
【解决方案3】:

现在是 2020 年,其中许多答案不再适用于 Sequelize v4/v5/v6 生态系统。

一个好的答案是使用sequelize-auto-migrations,但可能不足以在您的项目中使用。所以这里有更多的颜色......

设置

我的团队使用fork of sequelize-auto-migrations,因为原始 repo 尚未合并几个关键 PR。 #56#57#58#59

$ yarn add github:scimonster/sequelize-auto-migrations#a063aa6535a3f580623581bf866cef2d609531ba

编辑package.json:

"scripts": {
  ...
  "db:makemigrations": "./node_modules/sequelize-auto-migrations/bin/makemigration.js",
  ...
}

流程

注意:确保您使用的是 git(或某些源代码控制)和数据库备份,以便在出现严重问题时可以撤消这些更改。

  1. 删除所有旧迁移(如果存在)。
  2. 关闭.sync()
  3. 创建一个大规模迁移,迁移当前模型中的所有内容 (yarn db:makemigrations --name "mega-migration")。
  4. 提交您的01-mega-migration.js 和生成的_current.json
  5. 如果您之前运行过.sync() 或手写迁移,则需要通过将其名称插入到 SequelizeMeta 表中来“伪造”该大型迁移。 INSERT INTO SequelizeMeta Values ('01-mega-migration.js')
  6. 现在您应该可以正常使用它了……
  7. 对模型进行更改(添加/删除列、更改约束)
  8. 运行$ yarn db:makemigrations --name whatever
  9. 提交您的02-whatever.js 迁移以及对_current.json_current.bak.json 的更改。
  10. 通过正常的 sequelize-cli 运行迁移:$ yarn sequelize db:migrate
  11. 必要时重复 7-10

已知问题

  1. 重命名列将变成一对removeColumnaddColumn。这将丢失生产中的数据。您需要修改 up 和 down 操作以改用 renameColumn

对于那些不知道如何使用renameColumn 的人来说,sn-p 看起来像这样。 (为rollbackCommands 切换“column_name_before”和“column_name_after”)

{
    fn: "renameColumn",
    params: [
        "table_name",
        "column_name_before",
        "column_name_after",
        {
            transaction: transaction
        }
    ]
}
  1. 如果您有很多迁移,向下操作可能无法以顺序一致的方式完美地删除项目。

  2. 这个库的维护者没有主动检查它。因此,如果它不适合您开箱即用,您将需要寻找不同的社区分叉或其他解决方案。

【讨论】:

  • 我不断收到“UNKNOWN_VALUE: Unknown value: mega-migrations”错误。为什么会这样?
  • 哦。只是不要使用--name 选项。它是可选的。然后它将创建01-noname.js...,您可以手动重命名此文件。
  • 被卡住数小时后...谢谢!你是一个绅士和一个学者
  • 嘿!谢谢你。效果很好! :) 帮了我很多!我是 node-express+Sequelize 的新手。
  • 这在 v6 上对我有用。唯一的失败点是 Sequelize.NOW 没有很好地翻译,并且在迁移时出现语法错误。除此之外,我没有任何问题。谢谢!
【解决方案4】:

您现在可以使用 npm 包 sequelize-auto-migrations 自动生成迁移文件。 https://www.npmjs.com/package/sequelize-auto-migrations

使用 sequelize-cli,初始化你的项目

sequelize init

创建模型并将它们放入模型文件夹中。

安装 sequelize-auto-migrations:

npm install sequelize-auto-migrations

使用

创建初始迁移文件
node ./node_modules/sequelize-auto-migrations/bin/makemigration --name <initial_migration_name>

运行您的迁移:

node ./node_modules/sequelize-auto-migrations/bin/runmigration

您还可以从现有数据库自动生成模型,但这超出了问题的范围。

【讨论】:

  • 请注意,这不会产生向下迁移。
  • 这对我也不起作用。它使用我的表名生成一个迁移文件,仅此而已:没有列,没有架构,nada。
  • @CarlesAlcolea 我猜你的模型有问题。请发布一个单独的问题。
【解决方案5】:

我创建了一个小型工作“迁移文件生成器”。它使用sequelize db:migrate 创建可以正常工作的文件 - 即使使用外键!

你可以在这里找到它: https://gist.github.com/manuelbieh/ae3b028286db10770c81

我在一个包含 12 种不同模型的应用程序中对其进行了测试:

  • 字符串、文本、枚举、整数、布尔值、浮点数作为数据类型

  • 外键约束(偶数互易(用户属于团队,团队属于用户为所有者))

  • 具有namemethodunique 属性的索引

【讨论】:

  • 请注意任何尝试此脚本的人,它只适用于 mysql
  • 我如何运行这个?
【解决方案6】:

截至 2020 年 9 月 16 日,这些答案中的大多数都不太一致! 试试这个新的 npm 包

Sequelize-mig

它完成了 sequelize-auto-migrations 及其分支及其维护和记录中的大多数已知问题!

它的使用方式与已知的类似

安装:

npm install sequelize-mig -g / yarn global add sequelize-mig

然后像这样使用它

sequelize-mig migration:make -n <migration name>

【讨论】:

  • 这个工具很棒。它适用于您的 es6 模型,它可以检测重命名的列并且可以恢复迁移!
【解决方案7】:

如果您想在迁移的同时创建模型,请使用以下命令:-

sequelize model:create --name regions --attributes name:string,status:boolean --underscored

--underscored 它用于创建具有下划线的列,例如:- created_at、updated_at 或任何其他具有下划线的列,并支持用户定义的具有下划线的列。

【讨论】:

    【解决方案8】:

    虽然它不会自动生成,但在模型更改时生成新迁移的一种方法是: (假设您使用的是 stock sequelize-cli 文件结构,其中迁移和模型处于同一级别)

    1. (与 Manuel Bieh 的建议相同,但使用 require 而不是 import)在您的迁移文件中(如果您没有,您可以通过执行“sequelize migration:create”生成一个)具有以下代码:

      'use strict';
      var models = require("../models/index.js")
      module.exports = {
        up: function(queryInterface, Sequelize) {
          return queryInterface.createTable(models.User.tableName, 
            models.User.attributes);
        },
        down: function(queryInterface, Sequelize) {
          return queryInterface.dropTable('Users');
        }
      };
      
    2. 更改用户模型。

    3. 从数据库中删除表。
    4. 撤消所有迁移:sequelize db:migrate:undo:all
    5. 重新迁移以将更改保存在数据库中。 sequelize db:migrate

    【讨论】:

    • 我认为您的代码与models.sequelize.sync({force: true}) 类似(只是稍微复杂一点)。如果您更改模型,则无法更新您的架构,因为迁移已经运行(这就是您执行db:migrate:undo:all 的原因)。迁移应该对您的数据库架构进行版本控制。这是一个很好的例子(我学到了一些命令),但我不会在production 中使用它。
    • 我同意,这消除了迁移的力量。当模型代码更改时会发生什么?迁移将具有不同的行为。迁移几乎应该像 git commit 一样读起来。拥有一个为特定时间点生成迁移的脚本会很棒,而且它可能会利用您在这里所做的事情。
    • 您不应该使用 drop 来撤消迁移。这与迁移数据的目的不符。如果您撤消迁移,您将丢失所有用户数据,这不是迁移的目的。
    【解决方案9】:

    PaulMest 在此页面中的回答对我非常有用。 我使用了“sequelize-auto-migrations”,但它没有检测到我的更改。 我使用了'sequelize-auto-migrations-v2',这对我来说是正确的。 您可以通过以下方式安装它:

    npm install sequelize-auto-migrations-v2
    

    并通过以下方式使用它:

    node ./node_modules/sequelize-auto-migrations-v2/bin/makemigration
    

    【讨论】:

      【解决方案10】:

      我最近尝试了以下似乎效果很好的方法,尽管我不能 100% 确定是否有任何副作用:

      'use strict';
      
      import * as models from "../../models";
      
      module.exports = {
      
        up: function (queryInterface, Sequelize) {
      
          return queryInterface.createTable(models.Role.tableName, models.Role.attributes)
          .then(() => queryInterface.createTable(models.Team.tableName, models.Team.attributes))
          .then(() => queryInterface.createTable(models.User.tableName, models.User.attributes))
      
        },
      
        down: function (queryInterface, Sequelize) {
          ...
        }
      
      };
      

      当使用sequelize db:migrate 运行上述迁移时,我的控制台显示:

      Starting 'db:migrate'...
      Finished 'db:migrate' after 91 ms
      == 20160113121833-create-tables: migrating =======
      == 20160113121833-create-tables: migrated (0.518s)
      

      所有表格都在那里,一切(至少似乎)都按预期工作。如果定义正确,即使所有关联都存在。

      【讨论】:

      • 我已经修改了上面的脚本,为每个模型生成静态迁移文件(在 ./tmp 文件夹中):gist.github.com/manuelbieh/606710b003b5fe448100 - 正如我上面已经说过的:我不知道是否有负面影响,请谨慎使用!
      • 你的模型目录是什么样的?你还在用 sequelize 推荐的 index.js 脚本吗?
      • 我得到 [SyntaxError: Unexpected reserved word]
      • 警告:这与整个迁移模型背道而驰。如果您只想每次从模型中创建表,您可以使用 Sequelize 的 sync() 函数。但是,它并不能解决只需要在表中添加字段的生产服务器升级问题。实现这一点的唯一方法是手动编写迁移。迁移依赖于以前运行过的迁移。进行一次迁移并每次使用不同的模型重写它 - 根本不会运行,因为 SequelizeMeta 表表明迁移之前已经在该服务器上运行过。
      • 此外,想象一下这种情况:create-tables 迁移从模型创建所有表,就像它们在编译或构建安装包时的样子。您部署服务器并在部署期间运行迁移。稍后,您创建一个仅添加一个字段的迁移。你升级服务器。一切正常。然后你需要安装一个新的服务器。该服务器将运行已包含该字段的 create-tables 迁移,然后将运行仅添加一个字段的下一个迁移。由于该字段已存在,第二次迁移将失败。结论:迁移永远不会改变。
      【解决方案11】:

      另一种解决方案是将数据定义放入单独的文件中。

      这个想法是将模型和迁移通用的数据写入单独的文件,然后在迁移和模型中都需要它。然后在模型中我们可以添加验证,而迁移已经很好了。

      为了不让这篇文章被大量代码弄得乱七八糟,我写了一个 GitHub 要点。

      在这里查看:https://gist.github.com/igorvolnyi/f7989fc64006941a7d7a1a9d5e61be47

      【讨论】:

        猜你喜欢
        • 2021-03-17
        • 2020-02-01
        • 2016-09-27
        • 2020-05-29
        • 2020-11-09
        • 2015-10-12
        • 2019-09-27
        • 2018-07-14
        • 2019-05-31
        相关资源
        最近更新 更多