Sequelize.js:如何使用迁移和同步


137

我即将准备好启动我的项目。在启动后,我有很大的计划,数据库结构也将发生变化-现有表中的新列以及新表,以及与现有模型和新模型的新关联。

我还没有接触过Sequelize中的迁移,因为我只有测试数据,所以我不介意在每次数据库更改时都清除掉这些数据。

为此sync force: true,如果我更改了模型定义,则目前我正在运行我的应用程序。这将删除所有表并使它们从头开始。我可以忽略force使它仅创建新表的选项。但是,如果现有的更改,这将无用。

因此,一旦添加迁移,事情如何工作?显然,我不希望删除现有表(其中包含数据),所以这sync force: true是不可能的。在我帮助开发的其他应用程序(Laravel和其他框架)中,作为该应用程序部署过程的一部分,我们运行migration命令来运行所有待处理的迁移。但是在这些应用程序中,第一个迁移具有框架数据库,该数据库处于开发尚处于初期状态的状态-首次发布Alpha版本或其他内容。因此,即使是晚到派对的应用程序实例,也可以通过依次运行所有迁移,一口气掌握速度。

如何在Sequelize中生成这样的“首次迁移”?如果我没有,则该应用程序的新实例可能会没有骨架数据库来运行迁移,或者它将在开始时运行同步,并使所有数据库都处于新状态新表等,但是当它尝试运行迁移时,它们将变得毫无意义,因为它们是在原始数据库的基础上编写的,并且考虑到了每个连续的迭代。

我的思考过程:在每个阶段,初始数据库加上依次进行的每次迁移都应等于(正负数据)数据库, sync force: true运行。这是因为代码中的模型描述描述了数据库结构。因此,也许即使没有迁移表,我们也可以运行同步并将所有迁移标记为完成,即使它们没有运行。这是我需要做的(如何?),还是应该由Sequelize自己做,还是我吠错了树?如果我在正确的区域,那么肯定会存在一种自动生成大部分迁移的好方法,考虑到旧模型(通过提交哈希?甚至每个迁移都可以与提交相关联?),我承认我在想在不可移植的以git为中心的世界中)和新模型。它可以改变结构并生成将数据库从旧版本转换为新版本所需的命令,然后再返回,然后开发人员可以进行必要的调整(删除/转换特定数据等)。

当我使用--init命令运行sequelize二进制文件时,它给了我一个空的迁移目录。然后,当我运行sequelize --migrate它时,我得到一个SequelizeMeta表,里面没有任何东西,没有其他表。显然不是,因为该二进制文件不知道如何引导我的应用程序和加载模型。

我肯定错过了什么。

TLDR:如何设置我的应用程序及其迁移,以便可以更新实时应用程序的各种实例,以及没有旧启动数据库的全新应用程序?


2
我已经回答了与您的工作流程有关的问题,但理想情况下,应使用“迁移”设置所有表格。即使您现在正在使用sync,其思想是迁移“生成”了整个数据库,因此依赖框架本身就是一个问题。例如,Ruby on Rails工作流程对所有内容都使用了Migrations,一旦习惯了,它就很棒了。编辑:是的,我注意到这个问题已经很老了,但是鉴于从来没有令人满意的答案,人们可​​能会来这里寻求指导,所以我认为我应该有所作为。
Fernando Cordeiro

Answers:


88

产生“第一次迁移”

对于您而言,最可靠的方法是几乎手动执行此操作。我建议使用sequelize-cli工具。语法很简单:

sequelize init
...
sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text

这将同时创建模型和迁移。然后,手动将现有模型与sequ​​elize-cli生成的模型进行合并,并对迁移进行相同的处理。完成此操作后,擦除数据库(如果可能),然后运行

sequelize db:migrate

这将创建架构将进行迁移。您只需执行一次此操作即可切换到架构开发的正确过程(无sync:force,但具有权威性的迁移)。

稍后,当您需要更改架构时:

  1. 创建迁移: sequelize migration:create
  2. 在您的迁移文件中写下上下函数
  3. 根据您对迁移文件的更改,手动更改模型
  4. sequelize db:migrate

在生产中进行迁移

显然,您无法手动切换到生产服务器并运行迁移。使用umzug(Node.JS的框架无关迁移工具)在应用启动之前执行挂起的迁移。

您可以像这样获得待处理/尚未执行的迁移的列表:

umzug.pending().then(function (migrations) {
  // "migrations" will be an Array with the names of
  // pending migrations.
}); 

然后执行迁移(在callback中)。execute方法是一个通用函数,针对每个指定的迁移运行相应的函数:

umzug.execute({
  migrations: ['some-id', 'some-other-id'],
  method: 'up'
}).then(function (migrations) {
  // "migrations" will be an Array of all executed/reverted migrations.
});

我的建议是在应用启动之前尝试这样做,并尝试每次提供路线。像这样:

umzug.pending().then(function(migrations) {
    // "migrations" will be an Array with the names of
    // pending migrations.
    umzug.execute({
        migrations: migrations,
        method: 'up'
    }).then(function(migrations) {
        // "migrations" will be an Array of all executed/reverted migrations.
        // start the server
        app.listen(3000);
        // do your stuff
    });
});

我现在无法尝试,但乍一看应该可以。

UPD 2016年4月

一年后,仍然有用,因此分享我当前的提示。现在,我将sequelize-cli根据需要的实时依赖关系安装软件包,然后按以下方式修改NPM启动脚本package.json

...
"scripts": {
  "dev": "grunt && sequelize db:migrate && sequelize db:seed:all && node bin/www",
  "start": "sequelize db:migrate && sequelize db:seed:all && node bin/www"
},
...

我在生产服务器上唯一需要做的就是npm start。此命令将运行所有迁移,应用所有播种器并启动应用服务器。无需手动调用umzug。


3
这听起来像我要找的东西。它似乎不像“应该”那样神奇和自动,但是也许这是最好的。但是,我目前不与Sequelize合作,并且很快将无法进行测试。但是,如果其他人都认为此解决方案很好,我会接受这个答案。我仍然感到很难过,似乎没有办法根据模型版本之间的差异自动进行这些迁移。
tremby

4
@tremby是我使用的唯一真正了解模型的框架是Django。它分析模型,并询问“好吧,好像您在模型User中将字段名重命名为first_name。是否要为其创建迁移?” 在Django中,它几乎可以神奇地工作,我使用的其他工具都假定了与我上面提到的迁移方法相同的方法:您负责自己编写迁移,深刻理解要在当前模型状态中实际添加哪种类型的字段
f1nn 2015年

2
您可以摆脱,pending然后execute再做umzug.up().then(function (migrations) { app.listen(3000); })。根据umzug文档,它将执行所有待处理的迁移。
Vinay,2015年

完成迁移后,将字段添加到原始模型文件中的模式是否常见?
theptrk

@ f1nn我对您的设置有疑问,如何处理应用程序集群和可用性?我将pm2集成到我的工作流程中,也许它与npm脚本不能直接兼容。
diosney

17

我自己学习了一下,但是我认为我建议您现在使用迁移,以便您习惯迁移。我发现弄清楚迁移过程的最佳方法是查看由创建的表上的sql sequelize.sync(),然后从那里构建迁移。

migrations -c [migration name] 

将在迁移目录中创建模板迁移文件。然后,您可以使用需要创建的字段来填充它。该文件将需要包含createdAt/ updatedAt,关联所需的字段等。

对于初始表创建,向下应该具有:

migration.dropTable('MyTable');

但是对表结构的后续更新可以省去这一点,而只需使用alter table。

./node_modules/.bin/sequelize --migrate

创建示例如下所示:

module.exports = {
  up: function(migration, DataTypes, done) {
    migration.createTable(
        'MyTable',
        {
          id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true
          },
          bigString: {type: DataTypes.TEXT, allowNull: false},
          MyOtherTableId: DataTypes.INTEGER,
          createdAt: {
            type: DataTypes.DATE
          },
          updatedAt: {
            type: DataTypes.DATE
          }
        });
    done();
  },
  down: function(migration, DataTypes, done) {
    migration.dropTable('MyTable');
    done();
  }

要从头开始重做:

./node_modules/.bin/sequelize --migrate --undo
./node_modules/.bin/sequelize --migrate

我正在使用咖啡运行种子文件来填充以下表格:

coffee server/seed.coffee

它只有一个create函数,看起来像:

user = db.User.create
  username: 'bob'
  password: 'suruncle'
  email: 'bob@bob.com'
.success (user) ->
  console.log 'added user'
  user_id = user.id
  myTable = [
    field1: 'womp'
    field2: 'rat'

    subModel: [
      field1: 'womp'
     ,
      field1: 'rat'
    ]
  ]

切记不要sync()在模型中使用索引,否则它将覆盖迁移和种子的操作。

当然,文档位于http://sequelize.readthedocs.org/en/latest/docs/migrations/。但基本的答案是您必须自己添加所有内容以指定所需的字段。它不会为您做。


5
我并不是在问如何创建和运行迁移-正如您所指出的那样,这些都可以在文档中找到。我要问的是如何在可重用应用程序的上下文中使用它们,其中现有实例需要更新为较新的数据库版本,而新实例则需要从头开始创建该数据库。也许您正在回答这个问题,并说我根本不应该使用sync(),而是在迁移过程中进行初始数据库及其所有更改。那是你的意思吗
tremby 2014年

1
@tremby我认为这就是他的意思。您可以使用同步并处理结果,也可以手动创建所有迁移。我们的框架以Rails式的方式,基于模式差异生成迁移文件,如果Sequelize为我做到这一点,我将非常喜欢。手动进行迁移
实在

遗憾的是,您无法sequelize.sync()拥有一个生成的脚本来创建所有基本表和索引作为您的首次迁移(类似于rails schema.rb。)通读此文之后,看来最好的选择可能是导出初始架构作为sql,然后exec在第一次迁移时将其放入一个大语句中。然后,从那里开始针对已知的“ 1.0版”起点进行增量更改。
thom_nic

11

对于开发,现在有一个选项可以通过更改当前表的结构来同步它们。使用sequelize github repo中的最新版本,您现在可以使用alter参数运行同步。

Table.sync({alter: true})

来自文档的警告:

更改表格以适合模型。不建议用于生产。删除模型中已删除或类型​​更改的列中的数据。


3

现在有了新的续集迁移非常简单。

这是您可以执行的示例。

    'use strict';

    var Promise = require('bluebird'),
        fs = require('fs');

    module.exports = {
        up: function (queryInterface, Sequelize) {

            return Promise
                .resolve()
                .then(function() {
                    return fs.readFileSync(__dirname + '/../initial-db.sql', 'utf-8');
                })
                .then(function (initialSchema) {
                    return queryInterface.sequelize.query(initialSchema);
                })
        },

        down: function (queryInterface, Sequelize) {
            return Promise
                .resolve()
                .then(function() {
                    return fs.readFileSync(__dirname + '/../drop-initial-db.sql', 'utf-8');
                })
                .then(function (dropSql) {
                    return queryInterface.sequelize.query(dropSql);
                });
        }
    };

请记住,您必须设置:

"dialectOptions": { "multipleStatements": true }

在数据库配置上。


这不就是删除并重新创建数据库吗?
TWilly,2016年

我认为不建议使用初始的大sql文件,因为它将束缚适配器和数据库,否则将是数据库不可知的,因为您可以将其用于开发sqlite以及用于生产mariadb或其他。
diosney

2

使用版本。应用程序的版本取决于数据库的版本。如果新版本需要更新数据库,请为其创建迁移。

更新:我决定放弃迁移(KISS),并在需要时运行脚本update_db(sync forse:false)。


与我对user1916988回答的回答类似,您是否说我根本不应该使用sync(),并且我需要手动编写从旧版本模型的模式到新版本模型的迁移?
tremby

由于您的更新,我+1了。我实际上在想做同样的事情。当应用程序可以手动编写所有迁移文件时,这有点愚蠢,因此,我只需要编写一个手动脚本即可运行该应用程序并运行同步功能。
Sallar

2

有点晚了,在阅读了文档之后,您不需要进行您正在讨论的第一次迁移。您要做的就是调用sync以创建表。

sequelize.sync()

您还可以通过执行以下操作来运行简单的模型同步:

Project.sync()但是我认为这sequelize.sync()对于您的项目来说是一个更有用的一般情况(只要您在开始时就导入了好的模型)。

(摘自http://sequelizejs.com/docs/latest/models#database-synchronization

这将创建所有初始结构。之后,您仅需创建迁移即可演化模式。

希望能帮助到你。


7
我认为您没有非常彻底地阅读原始文章,或者我不太清楚。我不仅仅知道sequelize.sync()它的作用。
tremby 2014年

2

Sequelize可以异步运行任意SQL 。

我要做的是:

  • 生成迁移(用作第一次迁移);
  • 转储数据库,类似于: mysql_dump -uUSER -pPASS DBNAME > FILE.SQL
  • 可以将完整转储粘贴为文本(危险),也可以将带有完整转储的文件加载到Node中:
    • var baseSQL = "LOTS OF SQL and it's EVIL because you gotta put \ backslashes before line breakes and \"quotes\" and/or sum" + " one string for each line, or everything will break";
    • var baseSQL = fs.readFileSync('../seed/baseDump.sql');
  • 在Sequelize Migration上运行此转储:
module.exports = {
  up: function (migration, DataTypes) {
    var baseSQL = "whatever" // I recommend loading a file
    migration.migrator.sequelize.query(baseSQL);
  }
}

这应该注意设置数据库,尽管异步可能会成为问题。如果发生这种情况,我将研究一种推迟返回upsequelize函数直到异步query函数完成的方法。

更多关于mysql_dump:http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html
更多关于Sequelize迁移:http://sequelize.readthedocs.org/en/latest/docs/migrations/
更多从Sequelize Migration中运行SQL: https //github.com/sequelize/sequelize/issues/313


1

这是我当前的工作流程。我愿意提出建议。

  1. 设置sequelize以创建不存在的表
  2. 设置sequelize以删除并重新创建一个名为_blank的空白数据库中的所有表
  3. 使用mysql工具比较_blank并使用该工具同步更改。仍在寻找可以在Mac上执行此操作的负担得起的工具。MySql工作台看起来可以从现有架构中导入模型,然后同步架构。试图弄清楚如何通过命令行来简化此操作。

这样,您不必手动更新迁移表,也不必担心胖手指,但是仍然可以获得ORM。


1

朋友我也有同样的问题,并且设法了解如何使用它们。

我开始时没有ORM续集,因此我已经有了一个数据模型。
我必须使用sequelize-auto自动生成模型,并使用您创建的此文件https://gist.github.com/ahelord/a7a7d293695b71aadf04157f0f7dee64并同步({Force: false})来生成其迁移()
这是在dev.I中,我必须进行版本控制模型和迁移,并在每次提取代码时执行它们。

在生产环境中,服务器仅在楼上,因此您仅需运行迁移并在每次提交管理中就可以对模型进行版本控制而无需停止后端


1

我经历了这篇文章以及类似的问题,但它并没有真正为我解答。迁移对于扩展本地数据库和更新生产中的数据非常有用

我在这里问了这个问题,并回答了这个问题:用于处理迁移和初始化的工作流程?

用于未开发项目的TL-DR版本

  1. 按照传统上使用纯SQL脚本或使用gui工具的方式设计数据库架构
  2. 当您完成所有95%的数据库架构并对其满意时,继续进行操作,将整个.sql文件移到另一个上以进行续作
  3. 进行第一次迁移。运行sequelize init:migrate在你的任何文件夹models是在
  4. 制作第一个迁移文件。跑sequelize migration:generate --name [name_of_your_migration]
  5. 在该迁移文件中,将此代码放入其中
("use strict");
/**
 * DROP SCHEMA public CASCADE; CREATE SCHEMA public
 * ^ there's a schema file with all the tables in there. it drops all of that, recreates
 */
const fs = require("fs");
const initialSqlScript = fs.readFileSync("./migrations/sql/Production001.sql", {
  encoding: "utf-8",
});
const db = require("../models");
module.exports = {
  up: () => db.sequelize.query(initialSqlScript),
  down: () =>
    db.sequelize.query(`DROP SCHEMA public CASCADE; CREATE SCHEMA public;
`),
};

在此处输入图片说明

具有这种常规的文件夹结构

在此处输入图片说明

  1. 现在,您的续集设置已与您的初始数据库架构同步
  2. 当您要编辑数据库架构时,请再次运行 sequelize migration:generate --name [name_of_your_migration]
  3. 继续并在updown迁移路径上进行修改。这些是您的ALTER语句,用于更改列名称,DELETE,ADD列等
  4. sequelize db:migrate
  5. 您希望将模型同步到对远程数据库所做的更改,因此现在可以执行npm install sequelize-auto
  6. 这将读取数据库上的当前数据库架构并自动生成模型文件。使用类似于https://github.com/sequelize/sequelize-autosequelize-auto -o "./models" -d sequelize_auto_test -h localhost -u my_username -p 5432 -x my_password -e postgres下的命令

您可以使用git查看模型上的差异日志,应该只包含反映数据库模型更改的更改。另外请注意,models如果您使用,请勿直接修改sequelize auto,因为这样会为您生成它们。同样,您不再应该直接使用SQL文件修改数据库架构,这是一个选择,因为您可以导入这些.sql文件

现在,您的数据库架构是最新的,并且您已经正式迁移到仅顺序安排数据库迁移。

一切都受版本控制。这是数据库和后端开发人员的理想工作流程


0

还有更简单的方法(避免Sequalize)。像这样:

  1. 您在项目中键入命令:npm run migration:new

  2. 这将创建3个文件。一个js文件,以及两个分别命名为up和down的sql文件

  3. 您将SQL语句放在这些文件中,这是纯sql
  4. 然后键入:npm run migration:upnpm run migration:down

为此,请查看db-migrate模块。

一旦设置完成(这并不困难),更改数据库确实非常容易,并且节省了大量时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.