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

127

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

Sequelize CLI似乎可以做到这一点,根据这篇文章: “当你使用CLI生成模型时,你也将免费获得迁移脚本。”

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


4
这篇文章的链接无法使用。 :( - Sunil Sharma
1
请关注 https://github.com/sequelize/cli/issues/257 - Ben Creasy
11个回答

78

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

sequelize migration:generate --name [name_of_your_migration]

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


8
在进行数据库迁移时,特别是在添加或删除列时,需要注意以下内容,尽管它很少被谈及,但如果您想要更新生产环境中的这些内容,这些细节是必需的。 - BrinkDaDrink
9
您可以在项目根目录下运行 npx sequelize-cli migration:generate --name [name_of_your_migration]。但在此之前,您需要告诉 sequelize-cli 生成迁移文件的位置,sequelize-cli 使用名为 migrations-path 的配置项来指定该位置。参考链接:https://sequelize.org/master/manual/migrations.html#the--code--sequelizerc--code--file - Sento
62
这并没有回答问题,只是生成了一个框架,里面没有数据,而OP所问的正是数据。 - Neithan Max
2
谢谢,这真的很有用。无论如何,如果我们能做到OP所要求的,那就太棒了。 - Claudio Novoa

63

现在是2023年,这些回答已经不适用于Sequelize v4/v5/v6生态系统。

其中一个好的答案是使用sequelize-auto-migrations,但可能对您的项目不够明确。所以这里提供更多细节...

设置

我的团队使用sequelize-auto-migrations的分支,因为原始存储库还没有合并一些关键的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。这将在生产中丢失数据。您需要修改上下行操作,改用 renameColumn

对于那些不知道如何使用 renameColumn 的人,代码段应如下所示。(为 rollbackCommands 切换“column_name_before”和“column_name_after”)

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

  2. 此库的维护者不会主动检查它。因此,如果它不能直接为您工作,则需要找到一个不同的社区分支或另一个解决方案。


我只在 Sequelize 5.x 上进行了测试,对于我的团队来说它可以正常工作。 - PaulMest
1
哦。那就不要使用 --name 选项了。它是可选的。这样它就会创建 01-noname.js ... 然后你可以手动重命名这个文件。 - PaulMest
1
苦思冥想数小时后...谢谢!你真是位绅士和学者。 - Neithan Max
1
嘿!谢谢你。很好用! :) 帮了我很多忙!我是一个node-express+Sequelize的新手。 - Glenn Posadas
1
这在我的v6上运行良好。唯一的失败点是Sequelize.NOW翻译不好,在迁移时会出现语法错误。除此之外,我没有遇到任何问题。谢谢! - LucasP
显示剩余7条评论

60

无法为现有模型创建迁移脚本。

资源:

如果按传统方式进行,您需要通过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;
};

migrations/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);
  }
};


2
谢谢@Dor,我有几个关于使用sequelize同步功能的问题。据我所知,sequelize-cli在执行所有迁移时内部使用Umzug。你展示的例子真的帮助我入门了,但是如果我想要更改sequelize中的MyUser模型,并让sequelize cli为我创建迁移脚本,那么该怎么做呢?sequelize cli如何通过查看所有模型更改来创建迁移脚本? - Zeeshan Jan
23
一般来说,你需要区分同步能力和迁移。同步能力适用于新的数据库或演示,而迁移则适用于生产系统,因为你需要不断升级该系统并且不想丢失数据,此时迁移可能是唯一的选择。不幸的是,命令行界面只适用于创建基本模板,它没有运行任何特殊逻辑,并且不会扫描你的模型。(我也对此感到失望。)你需要创建迁移来转换架构/数据,并且你需要更改模型以代表最新的架构,就好像它一直存在一样。 - Dor Rotman
6
谢谢 @Dor,但编写迁移脚本似乎很费事。我希望可以避免编写迁移脚本,并且能够默认同步。 - Zeeshan Jan
1
然而,您链接的视频确实显示他能够从现有模型创建迁移(请参见他在5:40后键入stukko addMigration时)。 - sebastien.b
3
感谢@DorRotman - 我真的希望sequelize文档明确解决“您负责在迁移文件和模型文件之间维护一致性”的问题,因为这是一个非常重要的细节。 - xanderflood
显示剩余6条评论

29

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

使用sequelize-cli,通过以下命令初始化您的项目:

sequelize init
在你的models文件夹中创建你的模型。安装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

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


https://medium.com/riipen-engineering/squashing-migrations-with-sequelize-5478336247e5 - Muhammad Umer
请注意,这不会生成向下迁移。 - Thierry J.
2
它对我也不起作用。它生成了一个包含我的表名的迁移文件,但仅此而已:没有列,没有模式,什么都没有。 - Neithan Max
@CarlesAlcolea 我猜测你的模型有问题,请发布一个单独的问题。 - Kallaste

11

截至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>

1
这个工具非常好用。它可以与你的es6模型一起使用,可以检测重命名的列,并且可以还原迁移! - Pablo
2023年仍然是Sequelize v6的首选。 - Amine27

8

我创建了一个小型的“迁移文件生成器”,它可以创建文件,这些文件可以使用sequelize db:migrate进行完美工作,甚至包括外键!

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

我在一个应用程序中测试了它,该应用程序涵盖了12个不同的模型,包括:

  • STRING、TEXT、ENUM、INTEGER、BOOLEAN、FLOAT等数据类型

  • 带有外键约束(甚至是相互的(用户属于团队,团队属于用户作为所有者))

  • 具有namemethodunique属性的索引


6
注意:如果有人尝试使用此脚本,请注意,它仅适用于MySQL。 - Dakusan
我该如何运行这个程序? - CodeTrooper

6

如果您想创建模型并进行迁移,请使用以下命令:

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

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


3

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

  1. (Same as Manuel Bieh's suggestion, but using a require instead of an import) In your migration file (if you don't have one, you can generate one by doing "sequelize migration:create") have the following code:

    '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. Make a change to the User model.

  3. Delete table from database.
  4. Undo all migrations: sequelize db:migrate:undo:all
  5. Re-migrate to have changes saved in db. sequelize db:migrate

2
我认为你的代码与 models.sequelize.sync({force: true}) 做了类似的事情(只是稍微复杂一些)。如果你更改了模型,就没有办法更新你的模式,因为迁移已经运行过了(这就是为什么你要使用 db:migrate:undo:all)。迁移应该对你的数据库模式进行版本控制。这是一个不错的例子(我学到了一些命令),但我不会在 生产环境 中使用它。 - czerasz
1
我同意,这会削弱迁移的能力。当模型代码发生变化时会发生什么?迁移将具有不同的行为。迁移几乎应该像 git 提交一样阅读。如果有一个脚本可以为特定时间点生成迁移,那将是很棒的,它可能可以利用你在这里所做的工作。 - Zeke Nierenberg
不应该使用drop来撤销迁移。这与迁移数据的目的不符。如果您撤销迁移,将会丢失所有用户数据,这不是迁移的目的。 - Sebi2020

0

我最近尝试了以下方法,似乎运行良好,但我不能百分之百确定是否会有任何副作用:

'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)

所有的表格都在那里,一切(至少看起来是)按预期工作。即使所有关联都在那里,如果它们被正确定义的话。


2
我已经修改了上面的脚本,为每个模型(在./tmp文件夹中)生成静态迁移文件:https://gist.github.com/manuelbieh/606710b003b5fe448100 - 正如我之前所述:我不知道是否有任何负面影响,因此请谨慎使用! - Manuel Bieh
你的模型目录长什么样子?你还在使用sequelize推荐的index.js脚本吗? - trendsetter37
我收到了 [SyntaxError: Unexpected reserved word]。 - user3631341
8
警告:这与整个迁移模型相反。如果您只想每次从模型创建表格,可以使用 Sequelize 的 sync() 函数。但是,这并不能解决在生产服务器上升级只需要向表中添加字段的问题。唯一实现这一点的方法是手动编写迁移。迁移依赖于历史上运行的先前迁移。仅有一个迁移并每次用不同的模型重写它 - 将无法运行,因为 SequelizeMeta 表示该迁移已经在该服务器上运行过了。 - Dor Rotman
3
此外,想象一下这种情况:create-tables 迁移会从模型中创建所有表格,就像在编译或构建安装程序时看到的那样。您部署了一个服务器并在部署期间运行了迁移。稍后,您创建了一个仅添加字段的迁移。您升级了服务器。一切正常。然后您需要安装一个新服务器。该服务器将运行已经包含该字段的 create-tables 迁移,然后会运行下一个仅添加字段的迁移。第二个迁移将失败,因为该字段已经存在。结论:迁移永远不能改变。 - Dor Rotman
显示剩余2条评论

0

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

npm install sequelize-auto-migrations-v2

并通过以下方式使用:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接