¿Cómo hago una inserción masiva en mySQL usando node.js

123

¿Cómo se haría una inserción masiva en mySQL si se usa algo como https://github.com/felixge/node-mysql

crickeys
fuente
¿cual es tu problema? ¿Puedes hacerlo de la misma manera que con un comando sql? Simplemente inicie el siguiente comando cuando se haya completado previamente hasta que haya insertado todos los datos.
Andrey Sidorov
3
Tenía la impresión de que los insertos a granel son más rápidos que muchos insertos individuales.
crickeys
a nivel de cable son lo mismo. No hay 'inserción masiva' en el protocolo mysql
Andrey Sidorov
1
hay insertar múltiples en mySQL, simplemente use la palabra clave VALUES. dev.mysql.com/doc/refman/5.5/en/insert.html Las instrucciones INSERT que usan la sintaxis VALUES pueden insertar varias filas. Para hacer esto, incluya múltiples listas de valores de columna, cada una encerrada entre paréntesis y separadas por comas. Ejemplo: INSERTAR EN tbl_name (a, b, c) VALUES (1,2,3), (4,5,6), (7,8,9);
crickeys

Respuestas:

288

Las inserciones masivas son posibles mediante el uso de una matriz anidada, consulte la página de github

Las matrices anidadas se convierten en listas agrupadas (para inserciones masivas), por ejemplo, se [['a', 'b'], ['c', 'd']]convierten en('a', 'b'), ('c', 'd')

Simplemente inserta una matriz anidada de elementos.

Aquí se da un ejemplo.

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

Nota: valueses una matriz de matrices envueltas en una matriz

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

También hay un paquete node-msql totalmente diferente para la inserción masiva

Ragnar123
fuente
2
¿Proporciona esto las mismas protecciones que conn.execute()al usar declaraciones preparadas? Si no es así, ¿es posible utilizar declaraciones preparadas al hacer inserciones? Gracias.
Vigs
2
Sí, los valores se escapan con este método. Creo que es el mismo mecanismo que las declaraciones preparadas, que también usa connection.escape () internamente.
Ragnar123
77
Esto me confunde. ¿Por qué la matriz tiene que ser [[['a', 'b'], ['c', 'd']]] y no [['' a ',' b '], [' c ',' d ']] como dice la documentación?
Victorio Berra
12
Victorio Berra, se debe a que la matriz más externa es el único signo de interrogación coincidente en la declaración en general, no solo en la inserción. Por ejemplo, si tuviera dos marcadores de posición de signo de interrogación, tendría [param1, param2]. Diga "¿ACTUALIZAR Usuarios? DONDE ID =?", [Columnas, ID] Entonces, las columnas se expandirán al primer signo de interrogación y el ID al segundo.
Selay
3
Lamentablemente, esta respuesta no me funciona. Literalmente copié tu respuesta pero sin éxito.
Publiqué
19

La respuesta de @ Ragnar123 es correcta, pero veo que mucha gente dice en los comentarios que no está funcionando. Tuve el mismo problema y parece que necesitas envolver tu matriz de []esta manera:

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

Tiene que pasar como [pars]en el método.

Codendaal
fuente
66
Sí, por alguna razón tiene que ser una matriz, una matriz de matrices ...
Joe
También parece que requiere un singular en ?lugar de ??obtener la agrupación correcta.
Federico
15

Estaba buscando una respuesta sobre la inserción masiva de objetos.

La respuesta de Ragnar123 me llevó a hacer esta función:

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

¡Espero eso ayude!

Stephen Gibson
fuente
11

Me encontré con esto hoy ( mysql 2.16.0) y pensé en compartir mi solución:

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
fuente
3
Me gusta tu solución
Joe
¡Esta solución funcionó para mí! TY! POSTMAN: [{"textQuestionBuilderID": "5", "candidatoID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "candidatoID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "candidatoID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "candidatoID": "ABC123", "resultSelected ":" sfgh "}]
Brian
8

Todos los accesorios para Ragnar123 por su respuesta.

Solo quería expandirlo después de la pregunta hecha por Josh Harington para hablar sobre las ID insertadas.

Estos serán secuenciales. Vea esta respuesta: ¿una inserción de varias filas de MySQL toma ID de incremento automático secuencial?

Por lo tanto, puede hacer esto (observe lo que hice con el resultado.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);
  });

(Extraje los valores de una matriz de objetos que llamé persistentObjects).

Espero que esto ayude.

thewormsterror
fuente
¿estamos garantizados que en el caso de los insertos simultáneos la condición de carrera no mezclará los identificadores de inserto?
Purefan
1
@Purefan Según mis pruebas, sí, sin embargo, quién sabe si esto cambiará alguna vez.
thewormsterror
Tenga en cuenta, que esto sólo funciona si el tamaño de paso AUTO_INCREMENT está en su valor original de 1. Véase dev.mysql.com/doc/refman/5.7/en/...
Luksch
6

Este es un rápido "raw-copy-paste" recortado para empujar una columna de archivo en mysql con node.js> = 11

Fila de 250k en pocos segundos

'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
fuente
1
Esto funciona increíblemente bien, ¡gracias! Nota para los adaptadores: incluso si tiene varias columnas en INSERT, la clave es mantener esto solo ?después VALUES, sin corchetes. De esta forma, la matriz de matrices de columnas se puede procesar automáticamente en insertos masivos. Lo usó para analizar cientos de megabytes de registros de acceso en MySQL.
Alex Pakka
No me di cuenta por qué estabas rompiendo esto en pedazos hasta que lo intenté sin él. En algún momento, mi inserción se hizo demasiado grande para que el servidor la procesara de manera oportuna y recibí un error EPIPE. Romper el inserto en trozos arregla eso. :)
Kit Peters
4

En caso de que sea necesario, aquí es cómo resolvimos la inserción de la matriz

la solicitud es del cartero (Verá "invitados")

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

Y como escribimos

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
fuente
2

Si Ragnarla respuesta no te funciona. Probablemente, este sea el motivo (según mi experiencia):

  1. No estaba usando el node-mysqlpaquete como se muestra en mi Ragnar. Estaba usando el mysqlpaquete. Son diferentes (si no lo notaste, como yo). Pero no estoy seguro de si tiene algo que ver con el hecho de que ?no funciona, ya que parecía funcionar para muchas personas que usan el mysqlpaquete.

  2. Intenta usar una variable en lugar de ?

Lo siguiente funcionó para mí:

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

Espero que esto ayude a alguien.

Aswin Ramakrishnan
fuente
Creo que podrías olvidarte de poner el [] en valores. También me pasó a mí. Debería ser: conn.query (sql, [values], function () {}) En lugar de: conn.query (sql, values, function () {}) A pesar de que la variable de valores es una matriz, pero todavía tenemos para envolverlo con []
Anh Nguyen
El paquete node-mysql actual tiene una sintaxis totalmente diferente en comparación con el paquete mysql. El enlace del paquete node-mysql es npmjs.com/package/node-mysql El enlace del paquete mysql es github.com/mysqljs/mysql#escaping-query-values
Agnel Vishal
2

Algunas cosas que quiero mencionar es que estoy usando el paquete mysql para hacer una conexión con mi base de datos y lo que viste a continuación es un código de trabajo y está escrito para insertar una consulta masiva.

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
fuente
1

Estaba teniendo un problema similar Simplemente estaba insertando uno de la lista de matrices. Funcionó después de hacer los siguientes cambios.

  1. Pasó [params] al método de consulta.
  2. ¿Cambió la consulta de inserción (a, b) a valores de tabla1 (?) ==> inserción (a, b) a valores de tabla1? . es decir. Se eliminó la parálisis alrededor del signo de interrogación.

Espero que esto ayude. Estoy usando mysql npm.

usuario1998289
fuente
0

La inserción masiva en Node.js se puede hacer usando el siguiente código. Me he referido a muchos blogs para conseguir este trabajo.

por favor consulte este enlace también. https://www.technicalkeeda.com/nodejs-tutorials/insert-multiple-records-into-mysql-using-nodejs

El código de trabajo.

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

Espero que esto te ayudará.

Yadhu
fuente