Jak zrobić zbiorcze wstawianie w MySQL przy użyciu node.js.

123

Jak wykonać zbiorcze wstawianie do MySQL, używając czegoś takiego jak https://github.com/felixge/node-mysql

crickeys
źródło
jaki masz problem? Czy możesz to zrobić tak samo, jak za pomocą jednego polecenia sql? Po prostu uruchom następne polecenie, gdy poprzednie zakończyło się, aż do wstawienia wszystkich danych.
Andrey Sidorov
3
Miałem wrażenie, że wkładki BULK są szybsze niż wiele pojedynczych wkładek.
crickeys
na poziomie drutu są takie same. W protokole mysql nie ma „zbiorczego wstawiania”
Andrey Sidorov,
1
w mySQL jest wstaw wiele, po prostu używasz słowa kluczowego VALUES. dev.mysql.com/doc/refman/5.5/en/insert.html Instrukcje INSERT używające składni VALUES mogą wstawiać wiele wierszy. Aby to zrobić, uwzględnij wiele list wartości kolumn, każda ujęta w nawiasy i oddzielona przecinkami. Przykład: INSERT INTO tbl_name (a, b, c) VALUES (1,2,3), (4,5,6), (7,8,9);
crickeys

Odpowiedzi:

288

Wstawianie zbiorcze jest możliwe przy użyciu tablicy zagnieżdżonej, zobacz stronę github

Tablice zagnieżdżone są przekształcane w listy zgrupowane (w przypadku wstawiania zbiorczego), np. [['a', 'b'], ['c', 'd']]Zamienia się w('a', 'b'), ('c', 'd')

Po prostu wstawiasz zagnieżdżoną tablicę elementów.

Przykład podano tutaj

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

Uwaga: valuesto tablica tablic opakowana w tablicę

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

Istnieje również zupełnie inny pakiet node-msql do wstawiania zbiorczego

Ragnar123
źródło
2
Czy zapewnia to taką samą ochronę, jak conn.execute()użycie przygotowanych wyciągów? Jeśli nie, czy można wykorzystać przygotowane wyciągi podczas wstawiania? Dzięki.
Vigs
2
Tak, wartości są chronione tą metodą. Myślę, że jest to ten sam mechanizm, co przygotowane instrukcje, które również wewnętrznie wykorzystują connection.escape ().
Ragnar123
7
To jest dla mnie mylące. Dlaczego tablicą musi być [[['a', 'b'], ['c', 'd']]], a nie [['a', 'b'], ['c', 'd ']] jak mówi dokumentacja?
Victorio Berra
12
Victorio Berra, dzieje się tak dlatego, że najbardziej zewnętrzna tablica jest tą, która pasuje do znaków zapytania w całej instrukcji, a nie tylko we wstawce. Na przykład, gdybyś miał dwa symbole zastępcze ze znakami zapytania, to miałbyś [param1, param2]. Powiedz „UPDATE Users? WHERE ID =?”, [Column, ID] Więc kolumny zostaną rozwinięte do pierwszego znaku zapytania, a ID do drugiego.
Selay
3
Niestety ta odpowiedź nie działa dla mnie. Dosłownie skopiowałem twoją odpowiedź, ale bezskutecznie. Opublikowałem kolejne pytanie na stackoverflow.com/questions/41170849/ ...
Ivan Pandžić,
19

@ Ragnar123 odpowiedź jest poprawna, ale widzę wiele osób mówiących w komentarzach, że to nie działa. Miałem ten sam problem i wygląda na to, że musisz owinąć swoją tablicę w []ten sposób:

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]
];

Musi zostać przekazana jak [pars]do metody.

Codendaal
źródło
6
Tak, z jakiegoś powodu musi to być tablica, tablica tablic ...
Joe
Wygląda też na to, że wymaga liczby pojedynczej ?zamiast ??uzyskania prawidłowego grupowania.
Federico,
15

Rozglądałem się za odpowiedzią na temat zbiorczego wstawiania obiektów.

Odpowiedź udzielona przez Ragnar123 doprowadziła mnie do wykonania tej funkcji:

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

Mam nadzieję, że to pomoże!

Stephen Gibson
źródło
11

Natknąłem się na to dzisiaj ( mysql 2.16.0) i pomyślałem, że udostępnię moje rozwiązanie:

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
źródło
3
Podoba mi się twoje rozwiązanie
Joe
To rozwiązanie zadziałało dla mnie! TY! POSTMAN: [{"textQuestionBuilderID": "5", "kandydatID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "kandydat ID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "kandydatID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "kandydat ID": "ABC123", "resultSelected ":" sfgh "}]
Brian
8

Wszystkie rekwizyty dla Ragnara123 za jego odpowiedź.

Chciałem go tylko rozszerzyć po pytaniu zadanym przez Josha Haringtona, aby porozmawiać o włożonych identyfikatorach.

Będą one sekwencyjne. Zobacz tę odpowiedź: Czy wielorzędowe wstawianie MySQL przechwytuje sekwencyjne identyfikatory autoinkrementacji?

Dlatego możesz po prostu to zrobić (zwróć uwagę, co zrobiłem z result.insertId):

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

(Wyciągnąłem wartości z tablicy obiektów, które nazwałem persystentObjects.)

Mam nadzieję że to pomoże.

thewormsterror
źródło
czy mamy gwarancję, że w przypadku jednoczesnych wkładek warunek wyścigu nie będzie mieszał identyfikatorów wkładek?
Purefan
1
@Purefan Według moich testów tak, ale kto wie, czy to kiedykolwiek się zmieni.
thewormsterror
Zwróć uwagę, że zadziała to tylko wtedy, gdy rozmiar kroku auto_increment ma swoją pierwotną wartość 1. Zobacz dev.mysql.com/doc/refman/5.7/en/…
luksch
6

To jest szybkie „kopiowanie i wklejanie surowe” wycięte w celu przekazania kolumny pliku w mysql z node.js> = 11

250 tys. Rzędów w kilka sekund

'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
źródło
1
To działa zadziwiająco dobrze, dziękuję! Uwaga dla adapterów: nawet jeśli masz wiele kolumn w INSERT, kluczem jest zachowanie tej pojedynczej ?po VALUES, bez żadnych nawiasów. W ten sposób tablice tablic kolumn mogą być automatycznie przetwarzane w zbiorczych wstawieniach. Użyto go do analizy setek megabajtów dzienników dostępu w MySQL.
Alex Pakka
Nie zdawałem sobie sprawy, dlaczego rozbiłeś to na kawałki, dopóki nie spróbowałem bez. W pewnym momencie moja wstawka stała się zbyt duża, aby serwer mógł ją przetworzyć w odpowiednim czasie i pojawił się błąd EPIPE. Rozbicie wkładki na kawałki rozwiązuje ten problem. :)
Kit Peters
4

W przypadku, gdy jest to potrzebne, oto jak rozwiązaliśmy wstawianie tablicy

żądanie pochodzi od listonosza (będziesz patrzeć na „gości”)

 {
  "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]
}

I jak napisaliśmy scenariusz

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
źródło
2

Jeśli Ragnarodpowiedź nie działa dla Ciebie. Oto prawdopodobnie dlaczego (na podstawie mojego doświadczenia) -

  1. Nie korzystałem z node-mysqlpakietu, jak pokazano na moim Ragnar. Używałem mysqlpakietu. Są różne (jeśli nie zauważyłeś - tak jak ja). Ale nie jestem pewien, czy ma to coś wspólnego z ?niedziałającym mysqlpakietem , ponieważ wydawało się, że działa dla wielu osób korzystających z pakietu.

  2. Spróbuj użyć zmiennej zamiast ?

Poniższe działały dla mnie -

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

Mam nadzieję, że to komuś pomoże.

Aswin Ramakrishnan
źródło
Myślę, że możesz zapomnieć o przypisaniu [] do wartości. Mnie też się to przydarzyło. Powinien to być: conn.query (sql, [values], function () {}) Zamiast: conn.query (sql, values, function () {}) Mimo to zmienna values ​​jest tablicą, ale nadal mamy owinąć go []
Anh Nguyen
Obecny pakiet node-mysql ma zupełnie inną składnię niż pakiet mysql. Node-mysql link do pakietu to npmjs.com/package/node-mysql mysql link do pakietu to github.com/mysqljs/mysql#escaping-query-values
Agnel Vishal
2

Kilka rzeczy, o których chciałbym wspomnieć, to to, że używam pakietu mysql do nawiązywania połączenia z moją bazą danych, a to, co zobaczyłeś poniżej, to działający kod i napisany do wstawiania zapytania zbiorczego.

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
źródło
1

Miałem podobny problem. Po prostu wstawiał jeden z listy tablic. Zadziałało po wprowadzeniu poniższych zmian.

  1. Przekazano [parametry] do metody zapytania.
  2. Zmieniono zapytanie z insert (a, b) na wartości table1 (?) ==> insert (a, b) to table1 values? . to znaczy. Usunięto parantezę wokół znaku zapytania.

Mam nadzieję że to pomoże. Używam mysql npm.

user1998289
źródło
0

Wstawianie zbiorcze w Node.js można wykonać za pomocą poniższego kodu. Poleciłem wiele blogów, aby uzyskać tę pracę.

proszę odnieść się również do tego łącza. https://www.technicalkeeda.com/nodejs-tutorials/insert-multiple-records-into-mysql-using-nodejs

Działający kod.

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

Mam nadzieję, że to ci pomoże.

Yadhu
źródło