Knex: Importieren von MySQL-Daten aus einer .sql-Datei

Erstellt am 22. Aug. 2015  ·  16Kommentare  ·  Quelle: knex/knex

Ich habe eine vorhandene MySQL-Datenbank, mit der ich arbeiten muss. In der Entwicklung möchte ich Knex-Seeds verwenden, um diese Datenbank zu erstellen. Ich muss dies nicht mit Knex tun (ich kann den Koch verwenden, wenn ich muss), aber es wäre schön, dies tun zu können.

Ich erstelle eine .sql-Datei mit dem Befehl mysql -u user -p table > dump.sql . Die Ausgabe enthält Anweisungen zur bedingten Ausführung, die wie folgt aussehen:

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@<strong i="8">@CHARACTER_SET_CLIENT</strong> */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@<strong i="9">@CHARACTER_SET_RESULTS</strong> */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@<strong i="10">@COLLATION_CONNECTION</strong> */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@<strong i="11">@TIME_ZONE</strong> */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@<strong i="12">@UNIQUE_CHECKS</strong>, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@<strong i="13">@FOREIGN_KEY_CHECKS</strong>, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@<strong i="14">@SQL_MODE</strong>, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;

Knex kotzt auf diese Aussagen. Meine Fehlerausgabe von knex seed:run ist

rror: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET <strong i="19">@saved_cs_client</strong>     = @<strong i="20">@character_set_client</strong> */;
/*!40101 SET character_set' at line 9
    at Query.Sequence._packetToError (/vagrant/node_modules/mysql/lib/protocol/sequences/Sequence.js:48:14)
    at Query.ErrorPacket (/vagrant/node_modules/mysql/lib/protocol/sequences/Query.js:83:18)
    at Protocol._parsePacket (/vagrant/node_modules/mysql/lib/protocol/Protocol.js:274:23)
    at Parser.write (/vagrant/node_modules/mysql/lib/protocol/Parser.js:77:12)
    at Protocol.write (/vagrant/node_modules/mysql/lib/protocol/Protocol.js:39:16)
    at Socket.<anonymous> (/vagrant/node_modules/mysql/lib/Connection.js:96:28)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Socket.<anonymous> (_stream_readable.js:746:14)
    at Socket.EventEmitter.emit (events.js:92:17)
    at emitReadable_ (_stream_readable.js:408:10)
    at emitReadable (_stream_readable.js:404:5)
    at readableAddChunk (_stream_readable.js:165:9)
    at Socket.Readable.push (_stream_readable.js:127:10)
    at TCP.onread (net.js:526:21)
    at Protocol._enqueue (/vagrant/node_modules/mysql/lib/protocol/Protocol.js:135:48)
    at Connection.query (/vagrant/node_modules/mysql/lib/Connection.js:201:25)
    at /vagrant/node_modules/knex/lib/dialects/mysql/index.js:92:18
From previous event:
    at Client._query (/vagrant/node_modules/knex/lib/dialects/mysql/index.js:88:12)
    at Client.query (/vagrant/node_modules/knex/lib/client.js:127:24)
    at Runner.assign.query (/vagrant/node_modules/knex/lib/runner.js:118:24)
From previous event:
    at /vagrant/node_modules/knex/lib/runner.js:44:21
From previous event:
    at Runner.run (/vagrant/node_modules/knex/lib/runner.js:30:20)
    at Raw.Target.then (/vagrant/node_modules/knex/lib/interface.js:27:43)
    at Object.exports.seed (/vagrant/workbench-seeds/dev/workbench.js:5:20)
    at Object.<anonymous> (/vagrant/node_modules/knex/lib/seed/index.js:110:19)
From previous event:
    at /vagrant/node_modules/knex/lib/seed/index.js:109:23
    at arrayEach (/vagrant/node_modules/lodash/index.js:1289:13)
    at Function.<anonymous> (/vagrant/node_modules/lodash/index.js:3345:13)
    at Seeder._waterfallBatch (/vagrant/node_modules/knex/lib/seed/index.js:104:5)
    at Seeder.<anonymous> (/vagrant/node_modules/knex/lib/seed/index.js:64:19)
From previous event:
    at Seeder.<anonymous> (/vagrant/node_modules/knex/lib/seed/index.js:63:31)
From previous event:
    at Seeder._runSeeds (/vagrant/node_modules/knex/lib/seed/index.js:62:82)
    at Seeder.<anonymous> (/vagrant/node_modules/knex/lib/seed/index.js:24:17)
From previous event:
    at Seeder.<anonymous> (/vagrant/node_modules/knex/lib/seed/index.js:23:38)
From previous event:
    at Command.<anonymous> (/usr/local/lib/node_modules/knex/lib/bin/cli.js:134:34)
    at Command.listener (/usr/local/lib/node_modules/knex/node_modules/commander/index.js:301:8)
    at Command.EventEmitter.emit (events.js:98:17)
    at Command.parseArgs (/usr/local/lib/node_modules/knex/node_modules/commander/index.js:610:12)
    at Command.parse (/usr/local/lib/node_modules/knex/node_modules/commander/index.js:458:21)
    at Liftoff.invoke (/usr/local/lib/node_modules/knex/lib/bin/cli.js:142:13)
    at Liftoff.<anonymous> (/usr/local/lib/node_modules/knex/node_modules/liftoff/index.js:181:16)
    at module.exports (/usr/local/lib/node_modules/knex/node_modules/liftoff/node_modules/flagged-respawn/index.js:17:3)
    at Liftoff.<anonymous> (/usr/local/lib/node_modules/knex/node_modules/liftoff/index.js:174:9)
    at /usr/local/lib/node_modules/knex/node_modules/liftoff/index.js:148:9
    at /usr/local/lib/node_modules/knex/node_modules/v8flags/index.js:99:14
    at /usr/local/lib/node_modules/knex/node_modules/v8flags/index.js:38:7
    at process._tickCallback (node.js:415:13)
    at Function.Module.runMain (module.js:499:11)
    at startup (node.js:119:16)
    at node.js:902:3

Und meine Seed-Datei sieht so aus:

var fs = require('fs');

exports.seed = function(knex, Promise) {
    var sql = fs.readFileSync('./data/workbench.sql').toString();
    return Promise.join(
        knex.raw('DROP DATABASE workbench'),
        knex.raw('CREATE DATABASE workbench'),
        knex.raw(sql)
    );
};

Gibt es eine bessere Möglichkeit, eine .sql-Datei mit Knex zu importieren? Ist Knex nicht wirklich dafür da (dh missbrauche ich die Technologie)? Im Moment muss ich dieses Problem mit chef umgehen, aber ich bin daran interessiert, was ihr über diesen Anwendungsfall und dieses Problem denkt.

Hilfreichster Kommentar

Ich glaube, ich habe eine Lösung gefunden. Wenn Sie { multipleStatements: true } im Verbindungsobjekt hinzufügen, übergeben Sie die Knex-Instanz, die mehrere Anweisungen erlaubt und den Parse-Fehler nicht auslöst. Das Verbindungsobjekt würde dann ungefähr so ​​aussehen:

var knex = require('knex')({
  client: 'mysql',
  connection: {
    host     : '127.0.0.1',
    user     : 'your_database_user',
    password : 'your_database_password',
    database : 'myapp_test',
    multipleStatements: true
  }
});

Dann kannst du etwas Ähnliches machen wie @spruce-bruce

var fs = require('fs');

exports.seed = function(knex, Promise) {
    var sql = fs.readFileSync('./data/workbench.sql').toString();
    return knex.raw('DROP DATABASE workbench')
       .then(() => knex.raw('CREATE DATABASE workbench'))
       .then(() => knex.raw(sql))
};

Hinweis: Dies öffnet Sie für Unsicherheiten wie SQL-Injections (https://github.com/mysqljs/mysql#multiple-statement-queries). Aber ich denke, es ist in Ordnung, wenn Sie bedingt eine Verbindungskonfiguration für Ihre Testdatenbank verwenden.

Alle 16 Kommentare

Ich sitze im selben Boot, abzüglich der Option, mit dem Koch zu arbeiten

Ich habe auch eine vorhandene .sql-Datenbank, die ich als Seed für ein Knex-Projekt verwenden möchte. Oder konvertieren Sie das vorhandene Schema in Knex-Migrationen. Ich sehe keine eindeutig unterstützte Methode dafür

Anwendungsfall: Sie haben ein Basisschema in einer SQL-Datei und eine Reihe von Dummy-Daten für Tests definiert.
In jedem Test möchten Sie die Datenbank löschen und das Schema und die Dummy-Daten laden.

Irgendwelche Updates dazu?

@ph3b nein... keine Updates

<stating-the-obvious> Sie können ein externes Tool (Mysql-Client usw.) verwenden, um Basisdaten zu importieren und dann Knex-Migrationen darüber schreiben und diese separat ausführen </stating-the-obvious> .

Ich glaube, ich habe eine Lösung gefunden. Wenn Sie { multipleStatements: true } im Verbindungsobjekt hinzufügen, übergeben Sie die Knex-Instanz, die mehrere Anweisungen erlaubt und den Parse-Fehler nicht auslöst. Das Verbindungsobjekt würde dann ungefähr so ​​aussehen:

var knex = require('knex')({
  client: 'mysql',
  connection: {
    host     : '127.0.0.1',
    user     : 'your_database_user',
    password : 'your_database_password',
    database : 'myapp_test',
    multipleStatements: true
  }
});

Dann kannst du etwas Ähnliches machen wie @spruce-bruce

var fs = require('fs');

exports.seed = function(knex, Promise) {
    var sql = fs.readFileSync('./data/workbench.sql').toString();
    return knex.raw('DROP DATABASE workbench')
       .then(() => knex.raw('CREATE DATABASE workbench'))
       .then(() => knex.raw(sql))
};

Hinweis: Dies öffnet Sie für Unsicherheiten wie SQL-Injections (https://github.com/mysqljs/mysql#multiple-statement-queries). Aber ich denke, es ist in Ordnung, wenn Sie bedingt eine Verbindungskonfiguration für Ihre Testdatenbank verwenden.

@elhigu Das ist im Wesentlichen das, was ich getan habe, um den Fehler zu

Wir verwenden vagabundierende Maschinen für unsere Entwicklungsumgebung und die MySQL-Dump-Datei, die ich verwendet habe, war, eine Entwicklungsdatenbank einzurichten, die eng mit einer unserer Kundendatenbanken (einschließlich einiger Testdaten) übereinstimmt.

Wir verwenden vagrant und chef, um unsere Entwicklungs-/Qa-/Staging-/Produktionsumgebungen zu erstellen, und ich musste diese MySQL-Datenbank außer in der Produktion einrichten.

Am Ende habe ich meine MySQL-Entwicklungsdatenbank mit chef eingerichtet (was sowieso bereits die leere Datenbank erstellt. Es ging nur darum, die MySQL-Datenbank aus dem Dump zu importieren). Dies war letztendlich kein Problem, aber ich hätte es _bevorzugt_, dies mit Knex zu tun.

Ich muss den Vorschlag von @ph3b ausprobieren! Aber zu diesem Zeitpunkt ist mein Koch-Workaround seit einem Jahr in Ordnung, also ist es sicherlich nicht kritisch.

Wie lesen Sie die .sql-Datei mit Knex?

Ich habe die Datei einfach in den Speicher gelesen und den Inhalt an eine Raw-Knex-Abfrage übergeben

Während des Seedings möchte ich Fremdschlüsselprüfungen für alle Einfügungen im Kontext dieser Seed-Datei deaktivieren.

Weiß jemand wie ich das erreichen kann?

Gibt es so etwas wie dieses https://github.com/sequelize/sequelize-auto für Knex?
Ich migriere von Sequelize zu Knex, dieses "automatische" Tool hat mir bei meiner bestehenden MySQL-Datenbank sehr geholfen.

mit freundlichen Grüßen

@MichelDiz nein, es gibt keine Modelle oder Validatoren / Beziehungen usw. im Knex. Sie müssen Ihr DB-Schema kennen, das Sie über Knex verwenden.

@spruce-bruce Hier ist meine Lösung:

const cp = require('child_process');

cp.exec('mysql -uyour_user -pyour_password < your_file.sql', (error, stdout, stderr) => {
    if (error) throw error;
    console.log(`stdout: ${stdout}`);
    console.log(`stderr: ${stderr}`);
});

Ich poste es einfach auf SO: https://stackoverflow.com/a/47175173/3414180

Ich habe einen Prototyp dafür, https://gist.github.com/azlan/dfbfb8a2b519ee5fc2321ff10a0f91ef
Dieses Skript exportiert das *.sql-Schema in die Knex-Migration *.js

@azlan Ich denke nicht, dass das eine gute Idee ist (extrem instabil und begrenzt, Sie müssten einen ziemlich vollständigen MySQL-Parser implementieren, um diesen Ansatz zu vervollständigen) / auch nicht wirklich relevant, da nur versucht wird, das Schema zu extrahieren, anstatt SQL zu importieren Datenmüll.

var fs = require('fs');

exports.seed = function(knex, Promise) {
    var sql = fs.readFileSync('./data/workbench.sql').toString();
    return knex.raw('DROP DATABASE workbench')
       .then(() => knex.raw('CREATE DATABASE workbench'))
       .then(() => knex.raw(sql))
};

Die beste funktionierende Antwort erforderte eine leichte Optimierung, um Laufzeitprobleme rund um den relativen Pfad für die SQL-Datei und auch ein fehlendes "USE" zum Festlegen der Datenbank zu beheben.

Abgesehen davon ist diese Lösung der beste Weg, um eine rohe SQL-Datei zu importieren.

var path = require('path');
var fs = require('fs');

exports.up = function (knex, Promise) {
  var sql = fs.readFileSync(path.join(__dirname, './data/workbench.sql')).toString();
  return knex
    .raw('DROP DATABASE workbench')
    .then(() => knex.raw('CREATE DATABASE workbench'))
    .then(() => knex.raw('USE workbench'))
    .then(() => knex.raw(sql));
};

exports.down = async function (knex, Promise) {};
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen