Come faccio a eseguire un inserimento in blocco in mySQL usando node.js


123

Come si farebbe un inserimento in blocco in mySQL se si usasse qualcosa come https://github.com/felixge/node-mysql


Qual è il tuo problema? Puoi farlo allo stesso modo di un comando sql? Basta avviare il comando successivo al termine precedente fino a quando non hai inserito tutti i dati.
Andrey Sidorov

3
Avevo l'impressione che gli inserti BULK fossero più veloci di molti inserti singoli.
crickeys

a livello di filo sono la stessa cosa. Non esiste un "inserimento in blocco" nel protocollo mysql
Andrey Sidorov

1
c'è un inserimento multiplo in mySQL, devi semplicemente usare la parola chiave VALUES. dev.mysql.com/doc/refman/5.5/en/insert.html Le istruzioni INSERT che utilizzano la sintassi VALUES possono inserire più righe. A tale scopo, includere più elenchi di valori di colonna, ciascuno racchiuso tra parentesi e separato da virgole. Esempio: INSERT INTO tbl_name (a, b, c) VALUES (1,2,3), (4,5,6), (7,8,9);
crickeys

Risposte:


288

Gli inserimenti in blocco sono possibili utilizzando array nidificati, vedere la pagina github

Gli array annidati vengono trasformati in elenchi raggruppati (per inserimenti in blocco), ad esempio [['a', 'b'], ['c', 'd']]si trasforma in('a', 'b'), ('c', 'd')

Devi solo inserire un array nidificato di elementi.

Un esempio è fornito qui

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

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

Nota: valuesè un array di array racchiuso in un array

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

C'è anche un pacchetto node-msql completamente diverso per l'inserimento di massa


2
Questo fornisce le stesse protezioni del fare conn.execute()per utilizzare le dichiarazioni preparate? In caso contrario, è possibile utilizzare dichiarazioni preparate quando si fanno gli inserti? Grazie.
Vigs

2
Sì, i valori vengono sottoposti a escape con questo metodo. Penso che sia lo stesso meccanismo delle istruzioni preparate, che utilizza internamente anche connection.escape ().
Ragnar123

7
Questo mi confonde. Perché l'array deve essere [[['a', 'b'], ['c', 'd']]] e non [['a', 'b'], ['c', 'd ']] come dice la documentazione?
Victorio Berra

12
Victorio Berra, è perché l'array più esterno è quello che corrisponde ai punti interrogativi nell'istruzione in generale, non solo nell'inserto. Ad esempio, se avessi due segnaposto punto interrogativo, avresti [param1, param2]. Di '"AGGIORNA Utenti? WHERE ID =?", [Colonne, ID] Quindi, le colonne verranno espanse al primo punto interrogativo e l'ID al secondo.
Selay

3
Purtroppo questa risposta non funziona per me. Ho letteralmente copiato la tua risposta ma senza successo. Ho pubblicato un'altra domanda su stackoverflow.com/questions/41170849/…
Ivan Pandžić

19

@ Ragnar123 la risposta è corretta, ma vedo molte persone che dicono nei commenti che non funziona. Ho avuto lo stesso problema e sembra che tu debba avvolgere il tuo array in []questo modo:

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

Deve essere passato come [pars]nel metodo.


6
Sì, per qualche motivo deve essere un array, di un array di array ...
Joe

Sembra anche che richieda un singolare ?invece di ??ottenere il raggruppamento corretto.
Federico

15

Stavo cercando una risposta sull'inserimento di oggetti in blocco.

La risposta di Ragnar123 mi ha portato a realizzare questa funzione:

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

Spero che sia d'aiuto!


11

Mi sono imbattuto in questo oggi ( mysql 2.16.0) e ho pensato di condividere la mia soluzione:

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

3
Mi piace la tua soluzione
Joe

Questa soluzione ha funzionato per me! TY! POSTMAN: [{"textQuestionBuilderID": "5", "candidateID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "candidateID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "candidateID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "candidateID": "ABC123", "resultSelected ":" sfgh "}]
Brian

8

Tutti gli oggetti di scena a Ragnar123 per la sua risposta.

Volevo solo ampliarlo dopo la domanda posta da Josh Harington per parlare degli ID inseriti.

Questi saranno sequenziali. Vedi questa risposta: un inserto MySQL a più righe acquisisce ID sequenziali di incremento automatico?

Quindi puoi semplicemente farlo (nota cosa ho fatto con 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);
  });

(Ho estratto i valori da un array di oggetti che ho chiamato persistentObjects.)

Spero che questo ti aiuti.


siamo garantiti che in caso di inserimenti simultanei la race condition non mescolerà gli ID degli inserti?
Purefan

1
@Purefan Secondo i miei test si, però chissà se questo cambierà mai.
thewormsterror

Nota che questo funzionerà solo se la dimensione del passo auto_increment è sul suo valore originale di 1. Vedi dev.mysql.com/doc/refman/5.7/en/…
luksch

6

Questo è un veloce "raw-copy-paste" ritagliato per spingere una colonna di file in mysql con node.js> = 11

250.000 file in pochi secondi

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

1
Funziona incredibilmente bene, grazie! Nota per gli adattatori: anche se hai più colonne in INSERT, la chiave è mantenere questa singola ?dopo VALUES, senza parentesi. In questo modo array di array di colonne possono essere elaborati automaticamente in inserimenti di massa. L'ho usato per analizzare centinaia di megabyte di log di accesso in MySQL.
Alex Pakka

Non avevo capito perché lo stavi suddividendo in pezzi finché non l'ho provato senza. Ad un certo punto il mio inserto è diventato troppo grande per essere elaborato dal server in modo tempestivo e ho ricevuto un errore EPIPE. Spezzare l'inserto in pezzi lo risolve. :)
Kit Peters

4

Nel caso fosse necessario, ecco come abbiamo risolto l'inserimento di array

la richiesta è del postino (guarderai "ospiti")

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

E come abbiamo scritto

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

2

RagnarLa risposta di If non funziona per te. Probabilmente ecco perché (in base alla mia esperienza) -

  1. Non stavo usando il node-mysqlpacchetto come mostrato nel mio file Ragnar. Stavo usando il mysqlpacchetto. Sono diversi (se non l'hai notato, proprio come me). Ma non sono sicuro che abbia qualcosa a che fare con il ?non funzionamento, dal momento che sembrava funzionare per molte persone che utilizzavano il mysqlpacchetto.

  2. Prova a utilizzare una variabile invece di ?

Quanto segue ha funzionato per me:

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

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

Spero che questo aiuti qualcuno.


Penso che potresti dimenticare di mettere [] ai valori. È successo anche a me. Dovrebbe essere: conn.query (sql, [values], function () {}) Invece di: conn.query (sql, values, function () {}) Nonostante la variabile dei valori sia un array, ma abbiamo ancora per avvolgerlo con []
Anh Nguyen

L'attuale pacchetto node-mysql ha una sintassi completamente diversa rispetto al pacchetto mysql. Il collegamento al pacchetto node-mysql è npmjs.com/package/node-mysql Il collegamento al pacchetto mysql è github.com/mysqljs/mysql#escaping-query-values
Agnel Vishal

2

Poche cose che voglio menzionare è che sto usando il pacchetto mysql per effettuare una connessione con il mio database e quello che hai visto di seguito è codice funzionante e scritto per l'inserimento di query di massa.

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

1

Stavo avendo un problema simile. Ne stavo solo inserendo uno dall'elenco degli array. Ha funzionato dopo aver apportato le modifiche seguenti.

  1. Passato [params] al metodo di query.
  2. Modificata la query da insert (a, b) in table1 values ​​(?) ==> insert (a, b) into table1 values? . vale a dire. Rimossa la parentesi attorno al punto interrogativo.

Spero che questo ti aiuti. Sto usando mysql npm.


0

L'inserimento in blocco in Node.js può essere eseguito utilizzando il codice seguente. Ho fatto riferimento a molti blog per ottenere questo lavoro.

si prega di fare riferimento anche a questo collegamento. https://www.technicalkeeda.com/nodejs-tutorials/insert-multiple-records-into-mysql-using-nodejs

Il codice di lavoro.

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

Spero che questo ti possa aiutare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.