Sequelize.js:移行と同期の使用方法


137

プロジェクトを立ち上げる準備ができています。ローンチ後の大きな計画があり、データベース構造が変更される予定です。既存のテーブルと新しいテーブルの新しい列、および既存のモデルと新しいモデルへの新しい関連付けです。

データベースが変更されるたびに消去しても問題ないテストデータしか持っていないため、Sequelizeでの移行にはまだ触れていません。

そのため、現在sync force: true、モデル定義を変更した場合、アプリの起動時に実行しています。これにより、すべてのテーブルが削除され、最初から作成されます。force新しいテーブルのみを作成するオプションを省略できます。しかし、既存のものを変更した場合、これは役に立ちません。

では、マイグレーションを追加すると、どのように機能するのでしょうか?明らかに、既存のテーブル(データが含まれている)を消去したくないのでsync force: true、問題外です。アプリの展開手順の一部として開発を支援した他のアプリ(Laravelおよびその他のフレームワーク)では、migrateコマンドを実行して保留中の移行を実行します。しかし、これらのアプリでは、最初の移行にはスケルトンデータベースがあり、データベースは開発の初期の段階でした-最初のアルファリリースなどです。そのため、パーティーに遅れるアプリのインスタンスでさえ、すべてのマイグレーションを順番に実行することで、一度にスピードを上げることができます。

Sequelizeでこのような「最初の移行」を生成するにはどうすればよいですか?私が持っていない場合は、アプリの新しいインスタンスにある段階で移行を実行するためのスケルトンデータベースがないか、最初に同期が実行され、データベースがすべて新しい状態になります新しいテーブルなどですが、移行を実行しようとしても、元のデータベースと連続する各反復を考慮して記述されているため、意味がありません。

私の思考プロセス:すべての段階で、最初のデータベースと各移行のシーケンスは、次の場合に生成されるデータベースと同じ(プラスまたはマイナスのデータ)になるはずです。 sync force: true実行されます。これは、コード内のモデル記述がデータベース構造を記述しているためです。したがって、移行テーブルがない場合は、同期を実行して、すべての移行が実行されていなくても、完了とマークするだけです。これは私がする必要があるのですか(方法?)、またはSequelizeはこれを自分で行うことになっていますか、それとも間違ったツリーを吠えていますか?そして、私が適切な領域にいる場合、古いモデル(コミットハッシュによって?または各マイグレーションをコミットに関連付けることさえできる)を考えると、ほとんどのマイグレーションを自動生成するための素晴らしい方法があるはずです。移植性のないgit中心のユニバース)と新しいモデル。構造を比較し、データベースを古いものから新しいものに変換するために必要なコマンドを生成し、戻すことができます。その後、開発者は必要な調整(特定のデータの削除/移行など)を行うことができます。

--initコマンドでsequelizeバイナリを実行すると、空の移行ディレクトリが表示されます。次に走るとsequelize --migrateと、何も含まれていないSequelizeMetaテーブルが作成され、他のテーブルは作成されません。明らかにそうではありません。そのバイナリは、アプリをブートストラップしてモデルをロードする方法を知らないためです。

私は何かを逃しているに違いない。

TLDR:ライブアプリのさまざまなインスタンスを最新の状態にできるように、アプリとその移行を設定するにはどうすればよいですか。


2
私はあなたのワークフローに関して回答しましたが、理想的にはすべてのテーブルはマイグレーションを使用して設定する必要があります。今のところ使用syncしている場合でも、移行ではデータベース全体が「生成」されるため、スケルトンに依存すること自体が問題です。たとえば、Ruby on RailsワークフローはすべてにMigrationsを使用しており、慣れればかなり素晴らしいものになります。編集:はい、この質問はかなり古いことに気付きましたが、満足のいく答えは一度もなかったため、人々がガイダンスを求めてここに来る可能性があるので、私は貢献すべきだと考えました。
Fernando Cordeiro、2015

回答:


88

「最初の移行」の生成

あなたの場合、最も信頼できる方法は、ほとんど手動で行うことです。sequelize-cliツールを使用することをお勧めします。構文はかなり単純です:

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

これにより、モデルと移行の両方が作成されます。次に、sequelize-cliで生成された既存のモデルを手動でマージし、移行でも同じことを行います。これを実行した後、データベースをワイプし(可能な場合)、実行します

sequelize db:migrate

これにより、スキーマが移行されます。スキーマ開発の適切なプロセスに切り替えるには、これを1度だけ実行する必要があります(sync:forceなし、ただし権限のある移行あり)。

後でスキーマを変更する必要がある場合:

  1. 移行を作成します。 sequelize migration:create
  2. 移行ファイルに関数を上下に書き込む
  3. 移行ファイルの変更に応じて、手動でモデルを変更します
  4. 走る sequelize db:migrate

本番環境で移行を実行する

明らかに、運用サーバーにsshして手動で移行を実行することはできません。Node.JSのフレームワークに依存しない移行ツールであるumzugを使用して、アプリが起動する前に保留中の移行を実行します。

次のように、保留中/まだ実行されていない移行のリストを取得できます。

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月

1年後、まだ有用なので、私の現在のヒントを共有します。ここでは、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を使用していないため、これをすぐにテストすることはできません。しかし、この解決策が優れていることに他の誰かが同意した場合、私はこの答えを受け入れます。モデルバージョン間の差分からこれらの移行を自動的に行う方法がないように見えることは、まだ少し悲しいです。
震え2015

4
@tremby モデルを本当に理解するために私が使用した唯一のフレームワークはDjangoでした。モデルを分析し、「モデルユーザーのフィールド名をfirst_nameに変更したようです。移行を作成しますか?」のように尋ねます。ジャンゴでは、それはほとんど魔法の作品、私が使用した他のツールは、同じ移行は、私が上で言及したアプローチと仮定します。あなたは、移行を自分で書くための責任がある、深く理解し、あなたの現在のモデルの状態に実際のことを追加するためにどのような種類のものをフィールド
f1nn

2
あなたは取り除くことができpending、その後execute、ちょうど行いますumzug.up().then(function (migrations) { app.listen(3000); })。umzugのドキュメントによると、これにより保留中の移行がすべて実行されます。
Vinay 2015年

移行が完了したら、元のモデルファイルのスキーマにフィールドを追加することは一般的ですか?
theptrk

@ f1nnセットアップについて質問があります。アプリのクラスタリングと可用性をどのように処理しますか?私はワークフローにpm2を統合しますが、npmスクリプトでは簡単に機能しない可能性があります。
diosney 2016

17

自分でこれを学んでいるだけですが、慣れているので、今すぐマイグレーションを使用することをお勧めします。移行で何が行われるかを理解するための最良の方法は、によって作成されたテーブルのsqlを確認し、sequelize.sync()そこから移行を構築することです。

migrations -c [migration name] 

テンプレートマイグレーションファイルをmigrationsディレクトリに作成します。その後、作成する必要のあるフィールドを設定できます。このファイルには、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()をまったく使用すべきではないと言って、移行時に初期データベースとすべての変更を加えます。それはあなたが言っていることですか?
2014年

1
@tremby彼が言っていることだと思う。同期を使用して結果を処理するか、すべて手動で移行を作成できます。私たちのフレームワークは、Rails風の方法で、スキーマの差分に基づいて移行ファイルを生成します。Sequelizeがそれを実行してくれるなら、私は大好きです。手動で移行するのは
面倒すぎる

sequelize.sync()最初の移行としてすべてのベーステーブルとインデックスを作成するスクリプトを生成できないのは残念です(railsと同様schema.rbです)。これを読んだ後、最初のスキーマをエクスポートすることをお勧めします。 sqlとして、exec最初の移行で大きなステートメントに入れます。次に、既知の「バージョン1.0」の開始点に対して増分変更を実行します。
thom_nic 2017

11

以下のために開発、今その構造を変化させることによって、現在のテーブルを同期するオプションがあります。sequelize github repoの最新バージョンを使用して、alterパラメーターで同期を実行できるようになりました。

Table.sync({alter: true})

ドキュメントからの警告:

モデルに合わせてテーブルを変更します。本番環境での使用は推奨されません。削除された、またはモデルでタイプが変更された列のデータを削除します。


3

今、新しい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 }

データベース構成上。


これはデータベースを削除して再作成するだけではありませんか?
TWilly 2016年

最初の大きなsqlファイルを使用することは、アダプターとデータベースを結合するため、推奨されない方法だと思います。それ以外の場合は、データベースにとらわれないため、開発sqliteや本番用mariadbなどに使用できるためです。
diosney

2

バージョンを使用します。アプリケーションのバージョンは、データベースのバージョンによって異なります。新しいバージョンでデータベースの更新が必要な場合は、データベースの移行を作成します。

update:マイグレーション(KISS)を中止し、必要に応じてスクリプトupdate_db(sync forse:false)を実行することにしました。


user1916988の回答に対する私の回答と同様に、私はまったく使用すべきではなくsync()、古いバージョンのモデルのスキーマから新しいバージョンのモデルへの移行を手動で書き込む必要があると言っていますか?
2014

更新があったため、+ 1しました。私は実際に同じことを考えています。アプリができるときにすべての移行を手動で書くのは少しばかげているので、アプリを1回実行して同期機能を実行する手動スクリプトを作成するだけです。
Sallar

2

少し遅れて、ドキュメントを読んだ後は、最初に説明している移行を行う必要はありません。syncテーブルを作成するために呼び出すだけです。

sequelize.sync()

次のような方法で、単純なモデル同期を実行することもできます。

Project.sync()しかしsequelize.sync()、それはあなたのプロジェクトにとってより有用な一般的なケースだと思います(開始時に適切なモデルをインポートする限り)。

http://sequelizejs.com/docs/latest/models#database-synchronizationから取得)

これにより、すべての初期構造が作成されます。その後、スキーマを進化させるためにマイグレーションを作成するだけで済みます。

それが役に立てば幸い。


7
元の投稿を完全に読んだとは思わないか、おそらく私は十分に明確ではなかったでしょう。私は、それがsequelize.sync()何をしているかを知っている以上のものです。
14

2

Sequelizeは、任意のSQLを非同期で実行できます。

私がすることは:

  • マイグレーションを生成する(最初のマイグレーションとして使用するため);
  • 次のようなデータベースをダンプします。 mysql_dump -uUSER -pPASS DBNAME > FILE.SQL
  • 完全なダンプをテキスト(危険)として貼り付けるか、ノードに完全なダンプを含むファイルをロードします。
    • 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、非同期query関数が完了するまでsequelize関数の返送を延期する方法を検討します。

もっと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なしで始めたので、すでにデータモデルがありました。
私はsequelize-自動で自動的にモデルを作成し、作成することを、このファイルを使用して彼らの移行を生成しなければならなかったhttps://gist.github.com/ahelord/a7a7d293695b71aadf04157f0f7dee64(と同期して置く{Force: false}
これはdev.Iはバージョンなければならないだろうしていますモデルとマイグレーション、そしてコードをプルするたびにそれらを実行します。

本番環境ではサーバーは2階だけなので、バックエンドを停止せずにモデルをバージョン管理するので、移行を実行し、各コミットを管理するだけで済みます。


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. これで、sequelizeセットアップが初期データベーススキーマと同期されました
  2. データベーススキーマを編集する場合は、これを再度実行します sequelize migration:generate --name [name_of_your_migration]
  3. 先に進み、updown移行パスでここで変更を加えます。これらは、列名、DELETE、ADD列などを変更するためのALTERステートメントです
  4. 走る sequelize db:migrate
  5. モデルをリモートdbへの変更に同期させたいので、今できることはですnpm install sequelize-auto
  6. これにより、データベースの現在のデータベーススキーマが読み取られ、モデルファイルが自動生成されます。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を使用してモデルのdifflogを表示できます。データベースモデルの変更を反映する変更のみが必要です。補足として、modelsを使用する場合はを直接変更しないsequelize autoでください。これを使用すると、これらが生成されます。同様に、SQLファイルを使用してデータベーススキーマを直接変更する必要はなくなりました。これは、これらの.sqlファイルもインポートできるため、オプションです。

これでデータベーススキーマが最新になり、正式にデータベース移行の逐次化のみに移行しました。

すべてがバージョン管理されています。これはデータベースとバックエンド開発者にとって理想的なワークフローです


0

さらに簡単な方法があります(Sequalizeを避ける)。これは次のようになります:

  1. プロジェクト内にコマンドを入力します:npm run migrate:new

  2. これにより、3つのファイルが作成されます。jsファイルとupおよびdownという名前の2つのSQLファイル

  3. あなたはSQLステートメントをそれらのファイルに入れます、それは純粋なSQLです
  4. 次に、npm run migrate:upまたはnpm run migrate:downと入力します。

これが機能するためには、db-migrateモジュールをご覧ください。

(難しいことではありませんが)設定を取得したら、DBの変更は非常に簡単で、多くの時間を節約できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.