Wie generiere ich automatisch Migrationen mit Sequelize CLI aus Sequelize-Modellen?

75

Ich habe eine Reihe von Sequelize-Modellen. Ich möchte Migrationen verwenden, nicht DB Sync.

Sequelize CLI scheint dazu in der Lage zu sein, laut diesem Artikel : "Wenn Sie die CLI für die Modellgenerierung verwenden, erhalten Sie die Migrationsskripte ebenfalls kostenlos."

Wie werden die Migrationen mit Sequelize CLI aus vorhandenen Sequelize-Modellen automatisch generiert?

Michael Schmidt
quelle
2
Der Link "Dieser Artikel" funktioniert nicht. :(
Sunil Sharma
1
Behalten Sie github.com/sequelize/cli/issues/257 im
Ben Creasy

Antworten:

45

Wenn Sie Ihr Modell nicht von Grund auf neu erstellen möchten, können Sie mithilfe des folgenden CLI-Befehls manuell eine Migrationsdatei erstellen:

sequelize migration:generate --name [name_of_your_migration]

Dadurch wird eine leere Skelettmigrationsdatei generiert. Obwohl es Ihre Modellstruktur nicht in die Datei kopiert, finde ich es einfacher und sauberer als alles neu zu generieren. Hinweis: Stellen Sie sicher, dass Sie den Befehl aus dem enthaltenen Verzeichnis Ihres Migrationsverzeichnisses ausführen. Andernfalls generiert die CLI ein neues Migrationsverzeichnis für Sie

john_mc
quelle
4
Dies wird nie erwähnt, ist jedoch erforderlich, wenn Migrationen zum Hinzufügen oder Entfernen von Spalten durchgeführt werden, insbesondere wenn diese eine Produktionsumgebung aktualisieren sollen.
BrinkDaDrink
4
Sie können npx sequelize-cli migration:generate --name [name_of_your_migration]vom Stammverzeichnis Ihres Projekts aus ausführen . Bevor Sie dies tun, müssen Sie sequelize-cli mitteilen, wo Ihre Migrationen generiert werden sollen. Sequelize-cli verwendet die dafür aufgerufene Konfiguration migrations-path. sequelize.org/master/manual/…
Sento
6
Dies beantwortet die Frage überhaupt nicht. Es erzeugt nur ein Skelett, es sind keine Daten darin, was OP verlangt
Carles Alcolea
2
Danke, das war wirklich nützlich. Wie auch immer, es wäre süß, wenn wir tun könnten, was das OP verlangt.
Claudio Novoa
42

Sie können keine Migrationsskripte für vorhandene Modelle erstellen.

Ressourcen:

Wenn Sie den klassischen Weg gehen, müssen Sie die Modelle über die CLI neu erstellen:

sequelize model:create --name MyUser --attributes first_name:string,last_name:string,bio:text

Es werden diese Dateien generiert:

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

Dor Rotman
quelle
2
Danke @Dor ich habe ein paar Fragen zur Synchronisationsfunktionalität mit sequelize. Soweit ich weiß, verwendet sequelize-cli Umzug intern für alle Migrationen. Das Beispiel, das Sie gezeigt haben, hat mir wirklich beim Einstieg geholfen, aber wie ist das Verfahren für "Alter Table"? Angenommen, ich möchte das MyUser-Modell in "sequelize" ändern und clelize cli das Migrationsskript für mich erstellen lassen. Wie kann cli das Migrationsskript sequelize erstellen? Durchlaufen aller Modelländerungen.
Zeeshan Jan
16
Im Allgemeinen müssen Sie zwischen der Synchronisierungsfunktion, die für eine neue Datenbank oder eine Demo geeignet ist, und zwischen Migrationen unterscheiden. Wenn Sie ein Produktionssystem haben, das Sie kontinuierlich aktualisieren und die Daten nicht verlieren möchten, sind Migrationen wahrscheinlich Ihre einzige Option. Leider eignet sich die CLI nur zum Erstellen grundlegender Vorlagen, sie führt keine spezielle Logik aus und scannt Ihr Modell nicht. (Ich war auch davon enttäuscht.) Sie müssen die Migrationen erstellen, um das Schema / die Daten zu transformieren, und Sie müssen das Modell so ändern, dass es das neueste Schema darstellt, als ob es immer so gewesen wäre.
Dor Rotman
4
Vielen Dank an @Dor, aber es scheint viel Arbeit zu sein, das Migrationsskript für die Änderungen zu schreiben. Ich wünschte, die Migrationsskripte könnten irgendwie vermieden werden und die Synchronisierung könnte standardmäßig erfolgen.
Zeeshan Jan
Ich auch. Wenn Sie sich jedoch ActiveRecord- und Entity Framework-ORMs ansehen, ist dies das Muster, das sie ebenfalls implementieren.
Dor Rotman
1
Das Video, auf das Sie verlinken, zeigt jedoch , dass er Migrationen von vorhandenen Modellen erstellen kann (siehe, wenn er stukko addMigrationnach 5:40 tippte ).
sebastien.b
28

Es ist 2020 und viele dieser Antworten gelten nicht mehr für das Sequelize v4 / v5 / v6-Ökosystem.

Die eine gute Antwort lautet "verwenden" sequelize-auto-migrations, ist aber wahrscheinlich nicht vorgeschrieben genug, um sie in Ihrem Projekt zu verwenden. Also hier ist ein bisschen mehr Farbe ...

Installieren

Mein Team verwendet eine Gabelung,sequelize-auto-migrations da das ursprüngliche Repo nicht mit einigen kritischen PRs zusammengeführt wurde. # 56 # 57 # 58 # 59

$ yarn add github:scimonster/sequelize-auto-migrations#a063aa6535a3f580623581bf866cef2d609531ba

Bearbeiten package.json:

"scripts": {
  ...
  "db:makemigrations": "./node_modules/sequelize-auto-migrations/bin/makemigration.js",
  ...
}

Prozess

Hinweis: Stellen Sie sicher, dass Sie Git (oder eine Quellcodeverwaltung) und Datenbanksicherungen verwenden, damit Sie diese Änderungen rückgängig machen können, wenn etwas wirklich schief geht.

  1. Löschen Sie alle alten Migrationen, falls vorhanden.
  2. Ausschalten .sync()
  3. Erstellen Sie eine Mega-Migration, die alles in Ihren aktuellen Modellen migriert ( yarn db:makemigrations --name "mega-migration").
  4. Übernehmen Sie Ihr 01-mega-migration.jsund das _current.json, was generiert wird.
  5. Wenn Sie zuvor .sync()Migrationen ausgeführt oder handgeschrieben haben, müssen Sie diese Mega-Migration „fälschen“, indem Sie den Namen in Ihre SequelizeMeta-Tabelle einfügen. INSERT INTO SequelizeMeta Values ('01-mega-migration.js').
  6. Jetzt sollten Sie dies wie gewohnt verwenden können ...
  7. Nehmen Sie Änderungen an Ihren Modellen vor (Spalten hinzufügen / entfernen, Einschränkungen ändern)
  8. Lauf $ yarn db:makemigrations --name whatever
  9. Übernehmen Sie Ihre 02-whatever.jsMigration und die Änderungen an _current.jsonund _current.bak.json.
  10. Führen Sie Ihre Migration über das normale sequelize-cli aus : $ yarn sequelize db:migrate.
  11. Wiederholen Sie 7-10 nach Bedarf

Bekannte Fallstricke

  1. Das Umbenennen einer Spalte wird zu einem Paar von removeColumnund addColumn. Dadurch gehen Daten in der Produktion verloren. Sie müssen die Aufwärts- und Abwärtsaktionen ändern, um sie renameColumnstattdessen zu verwenden .

Für diejenigen, die die Verwendung verwirrt haben renameColumn, würde das Snippet so aussehen. (Schalter "Spaltenname_vor" und "Spaltenname_nach" für rollbackCommands)

{
    fn: "renameColumn",
    params: [
        "table_name",
        "column_name_before",
        "column_name_after",
        {
            transaction: transaction
        }
    ]
}
  1. Wenn Sie viele Migrationen haben, werden durch die Abwärtsaktion Elemente möglicherweise nicht perfekt in einer auftragskonsistenten Weise entfernt.

  2. Der Betreuer dieser Bibliothek überprüft sie nicht aktiv. Wenn es für Sie nicht sofort funktioniert, müssen Sie eine andere Community-Gabel oder eine andere Lösung finden.

PaulMest
quelle
Ich erhalte immer wieder den Fehler "UNKNOWN_VALUE: Unbekannter Wert: Mega-Migrationen". Warum passiert das?
YulePale
1
Oh. Verwenden Sie die --nameOption dann einfach nicht . Es ist optional. Es wird dann erstellt 01-noname.js... und Sie können diese Datei manuell umbenennen.
PaulMest
1
Nach stundenlangem Feststecken ... Danke! Sie sind ein Gentleman und ein Gelehrter
Carles Alcolea
1
Hallo! Danke dafür. Funktioniert gut! :) Hat mir viel geholfen! Ich bin ein Neuling in Node-Express + Sequelize.
Glenn Posadas
1
Dies funktionierte für mich auf Version 6. Der einzige Fehlerpunkt war, dass Sequelize.NOW nicht gut übersetzt ist und bei der Migration einen Syntaxfehler verursacht. Ansonsten hatte ich keine Probleme. Vielen Dank!
LucasP
24

Sie können jetzt das npm-Paket sequelize-auto-migrations verwenden, um automatisch eine Migrationsdatei zu generieren. https://www.npmjs.com/package/sequelize-auto-migrations

Initialisieren Sie Ihr Projekt mit sequelize-cli mit

sequelize init

Erstellen Sie Ihre Modelle und legen Sie sie in Ihrem Modellordner ab.

Installieren Sie sequelize-auto-migrations:

npm install sequelize-auto-migrations

Erstellen Sie eine erste Migrationsdatei mit

node ./node_modules/sequelize-auto-migrations/bin/makemigration --name <initial_migration_name>

Führen Sie Ihre Migration aus:

node ./node_modules/sequelize-auto-migrations/bin/runmigration

Sie können Ihre Modelle auch automatisch aus einer vorhandenen Datenbank generieren, was jedoch den Rahmen der Frage sprengt.

Kallaste
quelle
Beachten Sie, dass dies keine Downmigrationen generiert.
Thierry J.
1
Das funktioniert auch bei mir nicht. Es generiert eine Migrationsdatei mit meinen Tabellennamen, aber das war's: keine Spalten, kein Schema, nada.
Carles Alcolea
@ CarlesAlcolea Ich vermute, dass mit Ihren Modellen etwas nicht stimmt. Bitte posten Sie eine separate Frage.
Kallaste
7

Ich habe einen kleinen funktionierenden "Migrationsdateigenerator" erstellt. Es werden Dateien erstellt, die mit sequelize db:migrate- auch mit Fremdschlüsseln - einwandfrei funktionieren !

Sie finden es hier: https://gist.github.com/manuelbieh/ae3b028286db10770c81

Ich habe es in einer Anwendung mit 12 verschiedenen Modellen getestet, die Folgendes abdecken:

  • STRING, TEXT, ENUM, INTEGER, BOOLEAN, FLOAT als Datentypen

  • Fremdschlüsseleinschränkungen (auch wechselseitig (Benutzer gehört zum Team, Team gehört dem Benutzer als Eigentümer))

  • Indizes mit name, methodund uniqueEigenschaften

Manuel Bieh
quelle
3
Nur für alle, die dieses Skript
ausprobieren
Wie führe ich das aus?
CodeTrooper
2

Obwohl es nicht automatisch generiert wird, besteht eine Möglichkeit, neue Migrationen bei einer Änderung an einem Modell zu generieren, darin: (vorausgesetzt, Sie verwenden die Standard-Sequelize-Cli-Dateistruktur, in der sich Migrationen und Modelle auf derselben Ebene befinden)

  1. (Wie der Vorschlag von Manuel Bieh, jedoch mit einem Erfordernis anstelle eines Imports) In Ihrer Migrationsdatei (falls Sie keine haben, können Sie eine mit " sequelize migration:create" generieren ) haben Sie den folgenden 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. Nehmen Sie eine Änderung am Benutzermodell vor.

  3. Tabelle aus Datenbank löschen.
  4. Alle Migrationen rückgängig machen: sequelize db:migrate:undo:all
  5. Migrieren Sie erneut, um die Änderungen in der Datenbank zu speichern. sequelize db:migrate
T Ratnayake
quelle
2
Ich denke, Ihr Code macht etwas Ähnliches models.sequelize.sync({force: true})(nur ein bisschen komplexer). Wenn Sie das Modell ändern, können Sie Ihr Schema nicht aktualisieren, da die Migration bereits ausgeführt wird (aus diesem Grund tun Sie dies db:migrate:undo:all). Migrationen sollten Ihr DB-Schema versionieren. Es ist ein schönes Beispiel (ich habe nur wenige Befehle gelernt), aber ich würde es nicht verwenden production.
Czerasz
1
Ich stimme zu, dies nimmt die Macht der Migrationen weg. Was passiert, wenn sich der Modellcode ändert? Die Migration hat ein anderes Verhalten. Migrationen sollten fast wie ein Git-Commit gelesen werden. Es wäre fantastisch, ein Skript zu haben, das eine Migration für einen bestimmten Zeitpunkt generiert, und es könnte wahrscheinlich das nutzen, was Sie hier tun.
Zeke Alexandre Nierenberg
Sie sollten drop nicht verwenden, um die Migration rückgängig zu machen. Dies entspricht nicht dem Zweck der Datenmigration. Sie verlieren alle Ihre Benutzerdaten, wenn Sie eine Migration rückgängig machen, was nicht der Zweck von Migrationen ist.
Sebi2020
1

Wenn Sie ein Modell zusammen mit der Migration erstellen möchten, verwenden Sie diesen Befehl: -

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

- Unterstrichen wird verwendet, um Spalten mit Unterstrichen zu erstellen, wie z. B.: - created_at, updated_at oder jede andere Spalte mit Unterstrichen und unterstützt benutzerdefinierte Spalten mit Unterstrichen.

Shashikant Pandit
quelle
1

Ab dem 16.9.2020 sind die meisten dieser Antworten in keiner Weise zu konsistent! Probieren Sie dieses neue npm-Paket aus

Sequelize-mig

Es hat die bekanntesten Probleme bei der automatischen Fortsetzung von Migrationen und ihren Gabeln gelöst und wird gewartet und dokumentiert!

Es wird auf ähnliche Weise wie das bekannte verwendet

Installieren:

npm install sequelize-mig -g / yarn global add sequelize-mig

dann benutze es so

sequelize-mig migration:make -n <migration name>
MRVMV
quelle
-1

Ich habe kürzlich den folgenden Ansatz ausprobiert, der anscheinend gut funktioniert, obwohl ich nicht 100% sicher bin, ob es irgendwelche Nebenwirkungen geben könnte:

'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) {
    ...
  }

};

Wenn Sie die oben genannte Migration mit sequelize db:migrateausführen, sagt meine Konsole:

Starting 'db:migrate'...
Finished 'db:migrate' after 91 ms
== 20160113121833-create-tables: migrating =======
== 20160113121833-create-tables: migrated (0.518s)

Alle Tische sind da, alles (wie es scheint) funktioniert wie erwartet. Sogar alle Assoziationen sind da, wenn sie richtig definiert sind.

Manuel Bieh
quelle
2
Ich habe mein Skript oben geändert, um statische Migrationsdateien für jedes Modell (in einem ./tmpOrdner) zu generieren : gist.github.com/manuelbieh/606710b003b5fe448100 - wie oben bereits erwähnt: Ich habe keine Ahnung, ob es negative Nebenwirkungen gibt. Verwenden Sie es daher mit Vorsicht!
Manuel Bieh
Wie sieht Ihr Modellverzeichnis aus? Verwenden Sie immer noch das von indexelj empfohlene Skript index.js?
Trendsetter37
Ich erhalte [SyntaxError: Unerwartetes reserviertes Wort]
user3631341
8
WARNUNG: Dies widerspricht dem gesamten Migrationsmodell. Wenn Sie die Tabellen jedes Mal nur aus dem Modell erstellen möchten, können Sie die sync () - Funktion von Sequelize verwenden. Das Problem des Upgrades eines Produktionsservers, für den lediglich ein Feld zu einer Tabelle hinzugefügt werden muss, wird jedoch nicht gelöst. Die einzige Möglichkeit, dies zu erreichen, besteht darin, die Migrationen manuell zu schreiben. Migrationen basieren auf früheren, die historisch ausgeführt wurden. Eine einzelne Migration, die jedes Mal mit einem anderen Modell neu geschrieben wird, wird einfach nicht ausgeführt, da die SequelizeMeta-Tabelle angibt, dass die Migration bereits zuvor auf diesem Server ausgeführt wurde.
Dor Rotman
3
Stellen Sie sich außerdem dieses Szenario vor: Bei der Migration zum Erstellen von Tabellen werden alle Tabellen aus dem Modell erstellt, wie sie beim Kompilieren oder Erstellen des Installationspakets aussehen. Sie stellen einen Server bereit und führen die Migration während der Bereitstellung aus. Später erstellen Sie eine Migration, die nur ein Feld hinzufügt. Sie aktualisieren den Server. Funktioniert alles. Dann müssen Sie einen neuen Server installieren. Dieser Server würde die Migration zum Erstellen von Tabellen ausführen, die das Feld bereits enthält, und dann die nächste Migration ausführen, bei der nur ein Feld hinzugefügt wird. Die 2. Migration schlägt fehl, da das Feld bereits vorhanden ist. Fazit: Migrationen können sich nie ändern.
Dor Rotman
-2

Eine andere Lösung besteht darin, die Datendefinition in einer separaten Datei abzulegen.

Die Idee ist, Daten, die sowohl für das Modell als auch für die Migration gemeinsam sind, in eine separate Datei zu schreiben und sie dann sowohl für die Migration als auch für das Modell zu benötigen. Dann können wir im Modell Validierungen hinzufügen, während die Migration bereits abgeschlossen ist.

Um diesen Beitrag nicht mit tonnenweise Code zu überladen, habe ich einen GitHub-Inhalt geschrieben.

Sehen Sie es hier: https://gist.github.com/igorvolnyi/f7989fc64006941a7d7a1a9d5e61be47

Igor Volnyi
quelle