ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我还没有接触过 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 工作流程对所有事情都使用迁移,一旦你习惯了它就会非常棒。编辑:是的,我注意到这个问题已经很老了,但是鉴于从来没有一个令人满意的答案,人们可能会来这里寻求指导,我想我应该做出贡献。

f
f1nn

产生“第一次迁移”

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

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

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

sequelize db:migrate

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

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

创建迁移:sequelize migration:create 在你的迁移文件中写上和下函数根据你在迁移文件中的更改,手动更改你的模型运行 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
    });
});

我现在不能尝试这个,但乍一看它应该可以工作。

UPD 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 文档,这将执行所有挂起的迁移。
完成迁移后,将字段添加到原始模型文件中的架构中是否常见?
@f1nn 我对您的设置有疑问,您如何处理应用程序集群和可用性?我会将 pm2 集成到我的工作流程中,也许它不能直接与 npm 脚本一起使用。
J
J. Scott Elblein

只是自己学习这个,但我想我现在建议使用迁移,这样你就可以习惯它们了。我发现要弄清楚迁移中发生了什么,最好的办法是查看由 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 版”起点运行增量更改。
i
iwasrobbed

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

Table.sync({alter: true})

来自文档的警告:

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


V
Vincent Tang

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

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

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

像传统上使用纯 SQL 脚本或使用 gui 工具一样设计数据库架构 当您完成所有 95% 的数据库架构并且对它感到满意时,继续通过移动整个 .sql 将其移动到续集file over 进行第一次迁移。在模型所在的任何文件夹中运行 sequelize init:migrate 创建您的第一个迁移文件。运行 sequelize migration:generate --name [name_of_your_migration] 在那个迁移文件中,把这段代码放在那里

("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;
`),
};

https://i.stack.imgur.com/ldvsp.png

使用这种通用文件夹结构

https://i.stack.imgur.com/9sQU2.png

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

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

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

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


N
Nestor Magalhaes

现在用新的 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 或其他。
S
Sergey Karasev

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

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


与我对 user1916988 的回答类似,您是说我根本不应该使用 sync(),并且我需要手动编写从旧版本模型的架构到新版本模型的迁移?
由于您的更新,我 +1 ed。我实际上正在考虑做同样的事情。当应用程序可以做到这一点时手动编写所有迁移有点愚蠢,所以我只会制作一个手动脚本,运行应用程序一次并运行同步功能。
r
rmharrison

Sequelize 可以异步运行任意 SQL。

我会做的是:

生成迁移(用作第一次迁移);

转储您的数据库,例如:mysql_dump -uUSER -pPASS DBNAME > FILE.SQL

将完整转储粘贴为文本(危险)或在节点中加载带有完整转储的文件: var baseSQL = "LOTS OF SQL 它是邪恶的,因为您必须在换行符和 \"quotes\" 和/或 sum 之前放置 \ 反斜杠" + " 每行一个字符串,否则一切都会中断"; var baseSQL = fs.readFileSync('../seed/baseDump.sql');

var baseSQL = "大量的 SQL,这是邪恶的,因为你必须在换行符和 \"quotes\" 和/或 sum" + " 每行一个字符串之前放置 \ 反斜杠,否则一切都会中断";

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 迁移的更多信息:http://sequelize.readthedocs.org/en/latest/docs/migrations/
有关从 Sequelize 迁移中运行 SQL 的更多信息:https://github.com/sequelize/sequelize/issues/313


k
kiddouk

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

sequelize.sync()

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

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

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

这将创建所有初始结构。之后,您只需创建迁移即可发展您的模式。

希望能帮助到你。


我认为您没有非常彻底地阅读原始帖子,或者我可能不够清楚。我非常了解 sequelize.sync() 及其作用。
T
TWilly

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

设置 sequelize 以创建不存在的表 设置 sequelize 以删除并重新创建名为 _blank 的空白数据库中的所有表 使用 mysql 工具比较 _blank 并使用该工具同步更改。仍在寻找可以在 mac 上执行此操作的负担得起的工具。 MySql 工作台看起来您可以从现有模式中导入模型,然后同步模式。试图弄清楚如何通过命令行来做到这一点,以使其变得容易。

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


g
goto

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

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

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


A
Amiga500

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

您在项目中键入命令: npm run migrate:new 这将创建 3 个文件。一个js文件,还有两个名为up和down的sql文件你把你的sql语句放在那些文件里,就是纯sql然后你输入:npm run migrate:up or npm run migrate:down

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

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