Wie mache ich eine Masseneinfügung in mySQL mit node.js?

123

Wie würde man eine Masseneinfügung in mySQL durchführen, wenn man so etwas wie https://github.com/felixge/node-mysql verwendet?

Crickeys
quelle
was ist dein Problem? Können Sie es genauso machen wie mit einem SQL-Befehl? Starten Sie einfach den nächsten Befehl, wenn der vorherige abgeschlossen ist, bis Sie alle Daten eingefügt haben.
Andrey Sidorov
3
Ich hatte den Eindruck, dass BULK-Einsätze schneller sind als viele Einzeleinsätze.
Crickeys
auf Drahtniveau sind sie gleich. Es gibt keine "Masseneinfügung" im MySQL-Protokoll
Andrey Sidorov
1
In mySQL gibt es mehrere Einfügungen. Verwenden Sie einfach das Schlüsselwort VALUES. dev.mysql.com/doc/refman/5.5/en/insert.html INSERT-Anweisungen, die die VALUES-Syntax verwenden, können mehrere Zeilen einfügen. Fügen Sie dazu mehrere Listen mit Spaltenwerten hinzu, die jeweils in Klammern stehen und durch Kommas getrennt sind. Beispiel: INSERT INTO tbl_name (a, b, c) VALUES (1,2,3), (4,5,6), (7,8,9);
Crickeys

Antworten:

288

Bulk-Einfügungen sind mithilfe eines verschachtelten Arrays möglich (siehe Github-Seite)

Verschachtelte Arrays werden in gruppierte Listen umgewandelt (für Masseneinfügungen), z. B. [['a', 'b'], ['c', 'd']]in('a', 'b'), ('c', 'd')

Sie fügen einfach ein verschachteltes Array von Elementen ein.

Ein Beispiel finden Sie hier

var mysql = require('mysql');
var conn = mysql.createConnection({
    ...
});

var sql = "INSERT INTO Test (name, email, n) VALUES ?";
var values = [
    ['demian', '[email protected]', 1],
    ['john', '[email protected]', 2],
    ['mark', '[email protected]', 3],
    ['pete', '[email protected]', 4]
];
conn.query(sql, [values], function(err) {
    if (err) throw err;
    conn.end();
});

Hinweis: valuesist ein Array von Arrays, die in ein Array eingeschlossen sind

[ [ [...], [...], [...] ] ]

Es gibt auch ein völlig anderes Node-MSQL- Paket für das Einfügen von Massen

Ragnar123
quelle
2
Bietet dies den gleichen Schutz wie conn.execute()bei der Verwendung vorbereiteter Anweisungen? Wenn nicht, ist es möglich, vorbereitete Anweisungen beim Einfügen zu verwenden? Vielen Dank.
Vigs
2
Ja, mit dieser Methode werden Werte maskiert. Ich denke, es ist der gleiche Mechanismus wie vorbereitete Anweisungen, der auch intern connection.escape () verwendet.
Ragnar123
7
Das verwirrt mich. Warum muss das Array [[['a', 'b'], ['c', 'd']] und nicht [['a', 'b'], ['c', 'd ']] wie die Dokumentation sagt?
Victorio Berra
12
Victorio Berra, weil das äußerste Array dasjenige ist, das mit den Fragezeichen in der Anweisung im Allgemeinen übereinstimmt, nicht nur beim Einfügen. Wenn Sie beispielsweise zwei Fragezeichen-Platzhalter hätten, hätten Sie [param1, param2]. Sagen Sie "UPDATE Users? WHERE ID =?", [Spalten, ID]. Die Spalten werden also auf das erste Fragezeichen und die ID auf das zweite Fragezeichen erweitert.
Selay
3
Leider funktioniert diese Antwort bei mir nicht. Ich habe Ihre Antwort buchstäblich kopiert, aber ohne Erfolg. Ich habe eine weitere Frage auf stackoverflow.com/questions/41170849/… gestellt
Ivan Pandžić
19

@ Ragnar123 Antwort ist richtig, aber ich sehe viele Leute in den Kommentaren sagen, dass es nicht funktioniert. Ich hatte das gleiche Problem und es scheint, als müssten Sie Ihr Array []wie folgt einpacken :

var pars = [
    [99, "1984-11-20", 1.1, 2.2, 200], 
    [98, "1984-11-20", 1.1, 2.2, 200], 
    [97, "1984-11-20", 1.1, 2.2, 200]
];

Es muss wie [pars]in die Methode übergeben werden.

Codendaal
quelle
6
Ja, aus irgendeinem Grund muss es ein Array sein, aus einem Array von Arrays ...
Joe
Sieht auch so aus, als ob ein Singular erforderlich wäre, ?anstatt ??die richtige Gruppierung zu erhalten.
Federico
15

Ich habe mich nach einer Antwort zum Masseneinfügen von Objekten umgesehen.

Die Antwort von Ragnar123 führte mich zu dieser Funktion:

function bulkInsert(connection, table, objectArray, callback) {
  let keys = Object.keys(objectArray[0]);
  let values = objectArray.map( obj => keys.map( key => obj[key]));
  let sql = 'INSERT INTO ' + table + ' (' + keys.join(',') + ') VALUES ?';
  connection.query(sql, [values], function (error, results, fields) {
    if (error) callback(error);
    callback(null, results);
  });
}

bulkInsert(connection, 'my_table_of_objects', objectArray, (error, response) => {
  if (error) res.send(error);
  res.json(response);
});

Ich hoffe es hilft!

Stephen Gibson
quelle
11

Ich lief in diese heute ( mysql 2.16.0) und dachte , dass ich meine Lösung teilen würde:

const items = [
    {name: 'alpha', description: 'describes alpha', value: 1},
    ...
];

db.query(
    'INSERT INTO my_table (name, description, value) VALUES ?',
    [items.map(item => [item.name, item.description, item.value])],
    (error, results) => {...}
);
SnobOfTheGolfClub
quelle
3
Ich mag Ihre Lösung
Joe
Diese Lösung hat bei mir funktioniert! TY! POSTMAN: [{"textQuestionBuilderID": "5", "Kandidaten-ID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "Kandidaten-ID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "Kandidaten-ID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "Kandidaten-ID": "ABC123", "resultSelected" ":" sfgh "}]
Brian
8

Alle Requisiten an Ragnar123 für seine Antwort.

Ich wollte es nur nach der Frage von Josh Harington erweitern, um über eingefügte IDs zu sprechen.

Diese werden sequentiell sein. Siehe diese Antwort: Greift eine mehrzeilige MySQL-Einfügung sequentielle Autoincrement-IDs?

Daher können Sie dies einfach tun (beachten Sie, was ich mit der result.insertId gemacht habe):

  var statement = 'INSERT INTO ?? (' + sKeys.join() + ') VALUES ?';
  var insertStatement = [tableName, values];
  var sql = db.connection.format(statement, insertStatement);
  db.connection.query(sql, function(err, result) {
    if (err) {
      return clb(err);
    }
    var rowIds = [];
    for (var i = result.insertId; i < result.insertId + result.affectedRows; i++) {
      rowIds.push(i);
    }
    for (var i in persistentObjects) {
      var persistentObject = persistentObjects[i];
      persistentObject[persistentObject.idAttributeName()] = rowIds[i];
    }
    clb(null, persistentObjects);
  });

(Ich habe die Werte aus einem Array von Objekten abgerufen, die ich persistentObjects genannt habe.)

Hoffe das hilft.

thewormsterror
quelle
Ist uns garantiert, dass bei gleichzeitigen Einsätzen die Race-Bedingung die Insert-IDs nicht mischt?
Purefan
1
@Purefan Nach meinen Tests ja, aber wer weiß, ob sich das jemals ändern wird.
Thewormsterror
Beachten Sie, dass dies nur funktioniert, wenn die Schrittgröße für auto_increment auf dem ursprünglichen Wert von 1 liegt. Siehe dev.mysql.com/doc/refman/5.7/en/…
luksch
6

Dies ist ein schnelles "Raw-Copy-Paste", das abgeschnitten wurde, um eine Dateispalte in MySQL mit node.js> = 11 zu verschieben

250k Reihe in wenigen Sekunden

'use strict';

const mysql = require('promise-mysql');
const fs = require('fs');
const readline = require('readline');

async function run() {
  const connection = await mysql.createConnection({
    host: '1.2.3.4',
    port: 3306,
    user: 'my-user',
    password: 'my-psw',
    database: 'my-db',
  });

  const rl = readline.createInterface({ input: fs.createReadStream('myfile.txt') });

  let total = 0;
  let buff = [];
  for await (const line of rl) {
    buff.push([line]);
    total++;
    if (buff.length % 2000 === 0) {
      await connection.query('INSERT INTO Phone (Number) VALUES ?', [buff]);
      console.log(total);
      buff = [];
    }
  }

  if (buff.length > 0) {
    await connection.query('INSERT INTO Phone (Number) VALUES ?', [buff]);
    console.log(total);
  }

  console.log('end');
  connection.close();
}

run().catch(console.log);
Manuel Spigolon
quelle
1
Das funktioniert erstaunlich gut, danke! Hinweis für Adapter: Selbst wenn Sie mehrere Spalten in INSERT haben, besteht der Schlüssel darin, diese ?nachher VALUESohne Klammern beizubehalten. Auf diese Weise können Arrays von Spaltenarrays automatisch in Masseneinfügungen verarbeitet werden. Verwendet es, um Hunderte von Megabyte an Zugriffsprotokollen in MySQL zu analysieren.
Alex Pakka
Ich wusste nicht, warum du das in Stücke zerlegst, bis ich es ohne versuchte. Irgendwann wurde meine Beilage zu groß, als dass der Server sie rechtzeitig verarbeiten könnte, und ich erhielt einen EPIPE-Fehler. Das Aufteilen des Einsatzes in Stücke behebt das. :)
Kit Peters
4

Für den Fall, dass dies hier benötigt wird, haben wir das Einfügen eines Arrays gelöst

Anfrage ist vom Postboten (Sie werden sich "Gäste" ansehen)

 {
  "author_id" : 3,
  "name" : "World War II",
  "date" : "01 09 1939", 
  "time" : "16 : 22",
  "location" : "39.9333635/32.8597419",
  "guests" : [2, 3, 1337, 1942, 1453]
}

Und wie wir geschrieben haben

var express = require('express');
var utils = require('./custom_utils.js');

module.exports = function(database){
    var router = express.Router();

    router.post('/', function(req, res, next) {
        database.query('INSERT INTO activity (author_id, name, date, time, location) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name), date = VALUES(date), time = VALUES(time), location = VALUES(location)', 
                [req.body.author_id, req.body.name, req.body.date, req.body.time, req.body.location], function(err, results, fields){
            if(err){
                console.log(err);
                res.json({ status: utils.respondMSG.DB_ERROR });
            }
            else {
                var act_id = results.insertId;
                database.query('INSERT INTO act_guest (user_id, activity_id, status) VALUES ? ON DUPLICATE KEY UPDATE status = VALUES(status)', 
                        [Array.from(req.body.guests).map(function(g){ return [g, act_id, 0]; })], function(err, results, fields){
                    if(err){
                        console.log(err);
                        res.json({ status: utils.respondMSG.DB_ERROR });
                    }
                    else {
                        res.json({ 
                            status: utils.respondMSG.SUCCEED,
                            data: {
                                activity_id : act_id
                            }
                        });
                    }
                });
            }
        });
    });
    return router;
};
Sam
quelle
2

Wenn Ragnardie Antwort bei Ihnen nicht funktioniert. Hier ist wahrscheinlich warum (basierend auf meiner Erfahrung) -

  1. Ich habe das node-mysqlPaket nicht wie gezeigt verwendet Ragnar. Ich habe mysqlPaket verwendet. Sie sind anders (wenn du es nicht bemerkt hast - genau wie ich). Aber ich bin mir nicht sicher, ob es irgendetwas damit zu tun hat, dass es ?nicht funktioniert, da es für viele Leute, die das mysqlPaket verwenden, zu funktionieren schien .

  2. Versuchen Sie es mit einer Variablen anstelle von ?

Folgendes hat bei mir funktioniert -

var mysql = require('node-mysql');
var conn = mysql.createConnection({
    ...
});

var sql = "INSERT INTO Test (name, email, n) VALUES :params";
var values = [
    ['demian', '[email protected]', 1],
    ['john', '[email protected]', 2],
    ['mark', '[email protected]', 3],
    ['pete', '[email protected]', 4]
];
conn.query(sql, { params: values}, function(err) {
    if (err) throw err;
    conn.end();
});

Hoffe das hilft jemandem.

Aswin Ramakrishnan
quelle
Ich denke, Sie könnten vergessen, das [] auf Werte zu setzen. Das ist mir auch passiert. Es sollte sein: conn.query (sql, [values], function () {}) Anstelle von: conn.query (sql, values, function () {}) Trotzdem ist die Wertevariable ein Array, aber wir haben es noch um es mit [] zu verpacken
Anh Nguyen
Das aktuelle Node-MySQL-Paket hat eine völlig andere Syntax als das MySQL-Paket. Der Link für das Node-MySQL-Paket lautet npmjs.com/package/node-mysql. Der Link für das MySQL- Paket lautet github.com/mysqljs/mysql#escaping-query-values
Agnel Vishal
2

Einige Dinge, die ich erwähnen möchte, sind, dass ich das MySQL- Paket verwende, um eine Verbindung mit meiner Datenbank herzustellen. Was Sie unten gesehen haben, ist Arbeitscode, der für das Einfügen von Massenabfragen geschrieben wurde.

const values = [
  [1, 'DEBUG', 'Something went wrong. I have to debug this.'],
  [2, 'INFO', 'This just information to end user.'],
  [3, 'WARNING', 'Warning are really helping users.'],
  [4, 'SUCCESS', 'If everything works then your request is successful']
];

const query = "INSERT INTO logs(id, type, desc) VALUES ?";

const query = connection.query(query, [values], function(err, result) {
  if (err) {
    console.log('err', err)
  }

  console.log('result', result)
});
Sagar
quelle
1

Ich hatte ein ähnliches Problem. Es wurde nur eines aus der Liste der Arrays eingefügt. Es hat funktioniert, nachdem die folgenden Änderungen vorgenommen wurden.

  1. Übergab [params] an die Abfragemethode.
  2. Die Abfrage von Einfügen (a, b) in Tabellen1-Werte (?) ==> Einfügen (a, b) in Tabellen1-Werte geändert? . dh. Die Klammer um das Fragezeichen wurde entfernt.

Hoffe das hilft. Ich benutze MySQL npm.

user1998289
quelle
0

Die Masseneinfügung in Node.js kann mit dem folgenden Code erfolgen. Ich habe viele Blogs verwiesen, um diese Arbeit zu bekommen.

Bitte beziehen Sie sich auch auf diesen Link. https://www.technicalkeeda.com/nodejs-tutorials/insert-multiple-records-into-mysql-using-nodejs

Der Arbeitscode.

  const educations = request.body.educations;
  let queryParams = [];
  for (let i = 0; i < educations.length; i++) {
    const education = educations[i];
    const userId = education.user_id;
    const from = education.from;
    const to = education.to;
    const instituteName = education.institute_name;
    const city = education.city;
    const country = education.country;
    const certificateType = education.certificate_type;
    const studyField = education.study_field;
    const duration = education.duration;

    let param = [
      from,
      to,
      instituteName,
      city,
      country,
      certificateType,
      studyField,
      duration,
      userId,
    ];

    queryParams.push(param);
  }

  let sql =
    "insert into tbl_name (education_from, education_to, education_institute_name, education_city, education_country, education_certificate_type, education_study_field, education_duration, user_id) VALUES ?";
  let sqlQuery = dbManager.query(sql, [queryParams], function (
    err,
    results,
    fields
  ) {
    let res;
    if (err) {
      console.log(err);
      res = {
        success: false,
        message: "Insertion failed!",
      };
    } else {
      res = {
        success: true,
        id: results.insertId,
        message: "Successfully inserted",
      };
    }

    response.send(res);
  });

Hoffe das wird dir helfen.

Yadhu
quelle