【问题标题】:Sequelize.js: how to use migrations and syncSequelize.js:如何使用迁移和同步
【发布时间】:2014-02-02 01:15:23
【问题描述】:

我的项目即将启动。我对启动后有很大的计划,并且数据库结构将发生变化——现有表中的新列以及新表,以及与现有模型和新模型的新关联。

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

为此,如果我更改了模型定义,目前我的应用程序启动时正在运行sync force: true。这将删除所有表并从头开始创建它们。我可以省略 force 选项让它只创建新表。但是,如果现有的已经改变,这没有用。

那么,一旦我添加了迁移,事情会如何运作?显然我不希望现有的表(其中包含数据)被清除,所以sync force: true 是不可能的。在我帮助开发的其他应用程序(Laravel 和其他框架)上,作为应用程序部署过程的一部分,我们运行 migrate 命令来运行任何挂起的迁移。但在这些应用程序中,第一次迁移有一个框架数据库,该数据库处于开发早期的状态——第一个 alpha 版本或其他版本。因此,即使是迟到的应用实例也可以通过按顺序运行所有迁移来一次性加快速度。

如何在 Sequelize 中生成这样的“第一次迁移”?如果我没有,则应用程序的新实例将在某个方式下没有骨架数据库来运行迁移,或者它将在开始时运行同步并使数据库处于新状态新表等,但是当它尝试运行迁移时,它们就没有意义了,因为它们是用原始数据库和每次连续迭代编写的。

我的思考过程:在每个阶段,初始数据库加上顺序的每个迁移应该等于(加或减数据)sync force: true运行时生成的数据库。这是因为代码中的模型描述描述了数据库结构。所以也许如果没有迁移表,我们只是运行同步并将所有迁移标记为完成,即使它们没有运行。这是我需要做的(如何做?),还是 Sequelize 应该自己做,还是我在叫错树?如果我在正确的区域,肯定应该有一个很好的方法来自动生成大部分迁移,考虑到旧模型(通过提交哈希?或者甚至每个迁移都可以绑定到一个提交?我承认我在想在一个以 git 为中心的非便携式宇宙中)和新模型。它可以区分结构并生成将数据库从旧数据库转换为新数据库所需的命令,然后开发人员可以进行任何必要的调整(删除/转换特定数据等)。

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

我一定是错过了什么。

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

【问题讨论】:

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

标签: database node.js database-migration sequelize.js


【解决方案1】:

生成“第一次迁移”

在您的情况下,最可靠的方法是几乎手动进行。我建议使用sequelize-cli 工具。语法很简单:

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

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

sequelize db:migrate

这将创建架构将迁移。您应该只执行一次以切换到正确的架构开发过程(没有同步:强制,但具有权威迁移)。

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

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

在生产环境中运行迁移

显然,您不能通过 ssh 连接到生产服务器并手动运行迁移。使用 umzug,适用于 Node.JS 的与框架无关的迁移工具,在应用启动之前执行待处理的迁移。

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

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

然后执行迁移(内部回调)。 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
    });
});

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

2016 年 4 月更新

一年后,仍然有用,所以分享我目前的技巧。目前,我正在根据需要安装sequelize-clilive依赖,然后修改package.json中的NPM启动脚本如下:

...
"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。

【讨论】:

  • 这听起来像我要找的。它似乎并不像“应该”那样神奇和自动,但也许这是可以期望的最好的。但是,我目前没有与 Sequelize 合作,并且无法很快对其进行测试。但如果其他人同意这个解决方案很好,我会接受这个答案。我仍然觉得有点难过,似乎没有办法自动从模型版本之间的差异中进行这些迁移。
  • @tremby 我用过的唯一真正理解模型的框架是 Django。它分析模型并询问“好吧,您似乎将模型用户中的字段名称重命名为 first_name。您想为它创建迁移吗?”在 Django 中,它几乎可以神奇地工作,我使用的其他工具采用与我上面提到的相同的迁移方法:您负责自己编写迁移,深入了解要添加到当前模型状态的实际类型的哪个字段
  • 你可以去掉pending,然后去掉execute,只做umzug.up().then(function (migrations) { app.listen(3000); })。根据 umzug 文档,这将执行所有待处理的迁移。
  • 迁移完成后,在原模型文件的schema中添加字段是否常见?
  • @f1nn 我对您的设置有疑问,您如何处理应用程序集群和可用性?我会将 pm2 集成到我的工作流程中,也许它不适用于 npm 脚本。
【解决方案2】:

我自己只是在学习这个,但我认为我建议现在使用迁移,以便您习惯它们。我发现要弄清楚迁移中发生了什么,最好的办法是查看sequelize.sync() 创建的表上的 sql,然后从那里构建迁移。

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

这只是一个创建函数,看起来像:

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/。但基本答案是您必须自己添加所有内容以指定所需的字段。它不适合你。

【讨论】:

  • 我不是在问如何创建和运行迁移——正如您所指出的,这些都在文档中提供。我要问的是如何在可重用应用程序的上下文中使用它们,其中现有实例需要更新到较新的数据库版本,而新实例需要从头开始制作的数据库。或者也许您正在回答这个问题,并说我根本不应该使用sync(),并在迁移中对它进行初始数据库和所有更改。你说的是这个吗?
  • @tremby 我认为这就是他的意思。您可以使用同步并处理结果,也可以手动创建迁移。我们的框架以 Rails 风格的方式生成基于模式差异的迁移文件,如果 Sequelize 能为我这样做,我会很高兴。手动迁移太痛苦了……
  • 很遗憾,您不能 sequelize.sync() 然后生成一个脚本来创建所有基表和索引作为您的第一次迁移(类似于 rails 的 schema.rb。)通读后对此,您最好的选择似乎是将您的初始模式导出为 sql,然后在您的第一次迁移中将其放入一个大的 exec 语句中。然后从那里开始针对已知的“1.0 版”起点运行增量更改。
【解决方案3】:

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

Table.sync({alter: true})

来自文档的警告:

更改表格以适应模型。不推荐用于生产用途。删除模型中已移除或类型已更改的列中的数据。

【讨论】:

    【解决方案4】:

    我浏览了这篇文章和类似的问题,但它并没有真正为我解答。迁移对于启动本地数据库和更新生产中的数据很有用

    我在这里问了这个问题,也回答了:Workflow for handling sequelize migrations and initialization?

    用于新建项目的 TL-DR 版本

    1. 按照传统方式使用纯 SQL 脚本或使用 gui 工具来设计数据库架构
    2. 当您完成所有 95% 的数据库架构并且对它感到满意时,继续通过移动整个 .sql 文件来将其移动到续集
    3. 进行第一次迁移。在 models 所在的任何文件夹中运行 sequelize init:migrate
    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. 现在您的 sequelize 设置已与您的初始数据库架构同步
    2. 当你想编辑你的数据库模式时,再次运行sequelize migration:generate --name [name_of_your_migration]
    3. 继续在updown 迁移路径上进行修改。这些是用于更改列名、删除、添加列等的 ALTER 语句
    4. 运行sequelize db:migrate
    5. 您希望模型与远程数据库的更改同步,因此您现在可以使用npm install sequelize-auto
    6. 这将读取您数据库中的当前数据库架构并自动生成模型文件。使用与sequelize-auto -o "./models" -d sequelize_auto_test -h localhost -u my_username -p 5432 -x my_password -e postgres 类似的命令,在https://github.com/sequelize/sequelize-auto 下找到

    您可以使用 git 查看模型上的差异日志,应该只有反映数据库模型变化的变化。附带说明一下,如果您使用sequelize auto,请不要直接修改models,因为这会为您生成它们。同样,您不再应该直接使用 SQL 文件修改数据库架构,因为您也可以导入这些 .sql 文件

    现在您的数据库架构是最新的,并且您已正式转移到仅对数据库迁移进行后续处理。

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

    【讨论】:

      【解决方案5】:

      现在用新的 sequelize 迁移非常简单。

      这是你可以做的一个例子。

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

      关于数据库配置。

      【讨论】:

      • 这不只是删除并重新创建数据库吗?
      • 我认为不推荐使用初始的大 sql 文件,因为它会占用适配器和数据库,否则将与数据库无关,因为您可以用于开发 sqlite并用于生产 mariadb 或其他。
      【解决方案6】:

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

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

      【讨论】:

      • 与我对 user1916988 的回答类似,您是说我根本不应该使用sync(),并且我需要手动将旧版本模型的架构迁移到较新版本的型号?
      • 我 +1 编辑因为你的更新。我实际上正在考虑做同样的事情。当应用程序可以这样做时手动编写所有迁移有点愚蠢,所以我只会制作一个手动脚本,运行应用程序一次并运行同步功能。
      【解决方案7】:

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

      这应该负责设置数据库,尽管异步的事情可能会成为一个问题。如果发生这种情况,我会考虑一种方法来推迟返回 up sequelize 函数,直到异步 query 函数完成。

      关于 mysql_dump 的更多信息:http://dev.mysql.com/doc/refman/5.1/en/mysqldump.html
      有关 Sequelize Migrations 的更多信息:http://sequelize.readthedocs.org/en/latest/docs/migrations/
      更多关于在 Sequelize Migration 中运行 SQL:https://github.com/sequelize/sequelize/issues/313

      【讨论】:

        【解决方案8】:

        有点晚了,在阅读了文档之后,您不需要进行您所说的第一次迁移。您只需拨打sync 即可创建表格。

        sequelize.sync()

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

        Project.sync() 但我认为sequelize.sync() 对您的项目更有用(只要您在开始时导入好的模型)。

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

        这将创建所有初始结构。之后,您只需创建迁移即可改进您的架构。

        希望对你有帮助。

        【讨论】:

        • 我认为您没有很彻底地阅读原始帖子,或者我可能不够清楚。我非常了解sequelize.sync() 及其作用。
        【解决方案9】:

        这是我目前的工作流程。我愿意接受建议。

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

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

        【讨论】:

          【解决方案10】:

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

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

          在生产中,服务器仅在楼上,因此您只需运行迁移并在每次提交中进行管理,因为您将在不停止后端的情况下对模型进行版本化

          【讨论】:

            【解决方案11】:

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

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

            2. 这会创建 3 个文件。一个js文件,以及上下命名的两个sql文件

            3. 你把你的SQL语句放在那些文件里,就是纯sql
            4. 然后输入:npm run migrate:upnpm run migrate:down

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

            一旦设置好(这并不难),更改数据库真的很容易并且可以节省大量时间。

            【讨论】:

              猜你喜欢
              • 2014-10-10
              • 2019-08-12
              • 1970-01-01
              • 2012-03-10
              • 2012-06-05
              • 2020-12-31
              • 2017-05-26
              • 2014-01-22
              • 2021-05-15
              相关资源
              最近更新 更多