node.js를 사용하여 mySQL에서 대량 삽입을 수행하는 방법


123

https://github.com/felixge/node-mysql 과 같은 것을 사용하는 경우 mySQL에 대량 삽입을 수행하는 방법


당신의 문제는 무엇입니까? 하나의 SQL 명령과 동일한 방식으로 수행 할 수 있습니까? 모든 데이터를 삽입 할 때까지 이전 완료시 다음 명령을 시작하십시오.
Andrey Sidorov

3
저는 BULK 인서트가 많은 단일 인서트보다 빠르다는 인상을 받았습니다.
crickeys

와이어 수준에서 그들은 동일합니다. MySQL의 프로토콜에는 '대량 삽입은'없다
안드레이 시도 로프

1
mySQL에 다중 삽입이 있으며 단순히 VALUES 키워드를 사용합니다. VALUES 구문을 사용하는 dev.mysql.com/doc/refman/5.5/en/insert.html INSERT 문은 여러 행을 삽입 할 수 있습니다. 이렇게하려면 괄호로 묶고 쉼표로 구분 한 여러 열 값 목록을 포함합니다. 예 : INSERT INTO tbl_name (a, b, c) VALUES (1,2,3), (4,5,6), (7,8,9);
crickeys

답변:


288

중첩 배열을 사용하여 대량 삽입이 가능합니다. github 페이지를 참조하십시오.

중첩 된 배열은 그룹화 된 목록 (대량 삽입 용) [['a', 'b'], ['c', 'd']]으로 변환됩니다.('a', 'b'), ('c', 'd')

중첩 된 요소 배열을 삽입하기 만하면됩니다.

여기에 예가 나와 있습니다.

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

참고 : values배열에 래핑 된 배열의 배열입니다.

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

대량 삽입을위한 완전히 다른 node-msql 패키지도 있습니다.


2
이것은 conn.execute()준비된 진술을 사용 하는 것과 동일한 보호를 제공합니까 ? 그렇지 않다면, 삽입을 할 때 준비된 문장을 활용할 수 있습니까? 감사.
Vigs

2
예,이 방법으로 값이 이스케이프됩니다. 내부적으로 connection.escape ()를 사용하는 준비된 문과 동일한 메커니즘이라고 생각합니다.
Ragnar123

7
이것은 나에게 혼란 스럽습니다. 배열이 [[ 'a', 'b'], [ 'c', 'd가 아니라 [[['a ','b '], ['c ','d ']]] 여야하는 이유 ']] 문서가 말하는 것처럼?
Victorio Berra

12
Victorio Berra, 가장 바깥 쪽 배열이 삽입뿐만 아니라 일반적으로 문에서 일치하는 물음표이기 때문입니다. 예를 들어 두 개의 물음표 자리 표시자가 있으면 [param1, param2]가됩니다. "UPDATE Users? WHERE ID =?", [columns, ID]라고 말하면 열은 첫 번째 물음표로 확장되고 ID는 두 번째 물음표로 확장됩니다.
Selay 2015-08-27

3
불행히도이 답변은 저에게 효과가 없습니다. 나는 말 그대로 당신의 대답을 복사했지만 성공하지 못했습니다. 나는에 또 다른 질문을 게시 stackoverflow.com/questions/41170849/...
이반 Pandžić에게

19

@ Ragnar123 대답은 정확하지만 많은 사람들이 댓글에서 작동하지 않는다고 말하는 것을 봅니다. 나는 같은 문제가 있었고 다음과 같이 배열을 감싸 야 할 []것 같습니다.

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

[pars]메서드에 같이 전달되어야 합니다.


6
그래, 어떤 이유는 ... 배열의 배열의 배열 할 필요가

또한 올바른 그룹화를 얻는 ?대신 단수 를 요구하는 것처럼 보입니다 ??.
Federico

15

대량 삽입 개체에 대한 답변을 찾고있었습니다.

Ragnar123의 대답으로이 기능을 만들 수있었습니다.

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

도움이 되었기를 바랍니다.


11

나는 오늘 ( mysql 2.16.0) 이것을 만났고 내 솔루션을 공유 할 것이라고 생각했습니다.

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
나는 당신의 해결책을 좋아합니다
Joe

이 솔루션은 저에게 효과적이었습니다! 타이! 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

Ragnar123에 대한 모든 소품.

삽입 된 ID에 대해 Josh Harington이 질문 한 후 확장하고 싶었습니다.

이들은 순차적입니다. 이 답변을 참조하십시오 : MySQL 다중 행 삽입은 순차적 자동 증가 ID를 가져 옵니까?

따라서이 작업을 수행 할 수 있습니다 (내가 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);
  });

(persistentObjects라고 부르는 객체 배열에서 값을 가져 왔습니다.)

도움이 되었기를 바랍니다.


동시 삽입의 경우 경쟁 조건이 삽입 ID를 혼합하지 않을 것이라는 보장이 있습니까?
Purefan 2016

1
@Purefan 내 테스트에 따르면 예, 그러나 이것이 변경 될지 누가 압니까?
thewormsterror

참고 AUTO_INCREMENT 단계 크기 1. 참조의 원래 값에 경우에만 작동합니다 dev.mysql.com/doc/refman/5.7/en/...
luksch

6

이것은 node.js> = 11을 사용하여 mysql의 파일 열을 푸시하기위한 빠른 "raw-copy-paste"입니다.

몇 초 만에 25 만 행

'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
이것은 놀랍게도 잘 작동합니다. 감사합니다! 어댑터에 대한 참고 사항 : INSERT에 여러 열이 있더라도 핵심은 대괄호없이이 단일 열을 ?뒤에 유지하는 것 VALUES입니다. 이러한 방식으로 열 배열의 배열이 대량 삽입에서 자동으로 처리 될 수 있습니다. MySQL에서 수백 메가 바이트의 액세스 로그를 분석하는 데 사용되었습니다.
Alex Pakka 2019-08-08

나는 그것을 시도하기 전까지 당신이 이것을 덩어리로 나누는 이유를 깨닫지 못했습니다. 어느 시점에서 삽입물이 너무 커서 서버가 적시에 처리 할 수 ​​없었고 EPIPE 오류가 발생했습니다. 인서트를 덩어리로 나누면 문제가 해결됩니다. :)
Kit Peters

4

여기에 필요한 경우 배열 삽입을 해결하는 방법입니다.

우편 배달부에서 요청한 것입니다 ( "guests"참조).

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

그리고 스크립트 작성 방법

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

경우 Ragnar의 대답은 당신을 위해 작동하지 않습니다. 아마도 그 이유는 다음과 같습니다 (내 경험을 바탕으로)-

  1. node-mysql표시된대로 패키지를 사용하지 않았습니다 Ragnar. 나는 mysql패키지 를 사용하고 있었다 . 그들은 다릅니다 (당신이 눈치 채지 못했다면-나처럼). 그러나 패키지를 ?사용하는 많은 사람들에게 작동하는 것처럼 보였기 때문에 작동하지 않는 것과 관련이 있는지 확실하지 않습니다 mysql.

  2. 대신 변수를 사용해보십시오. ?

다음은 나를 위해 일했습니다.

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

이것이 누군가를 돕기를 바랍니다.


값에 []를 넣는 것을 잊었을 것 같습니다. 나에게도 일어났다. conn.query (sql, [values], function () {}) 대신 : conn.query (sql, values, function () {}) 값 변수는 배열이지만 여전히 []로 포장하기
안 구엔에게

현재 node-mysql 패키지는 mysql 패키지와 완전히 다른 구문을 가지고 있습니다. node-mysql 패키지 링크는 npmjs.com/package/node-mysql입니다. mysql 패키지 링크는 github.com/mysqljs/mysql#escaping-query-values입니다
Agnel Vishal

2

내가 언급하고 싶은 몇 가지 사항은 데이터베이스와 연결하기 위해 mysql 패키지를 사용하고 있으며 아래에서 보신 것은 작업 코드이며 대량 쿼리 삽입을 위해 작성되었습니다.

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

비슷한 문제가 발생했습니다. 배열 목록에서 하나를 삽입했습니다. 다음과 같이 변경 한 후에 작동했습니다.

  1. 쿼리 메서드에 [params]를 전달했습니다.
  2. 쿼리를 삽입 (a, b)에서 table1 값으로 변경했습니다 (?) ==> insert (a, b)를 table1 값으로? . 즉. 물음표 주변의 괄호를 제거했습니다.

도움이 되었기를 바랍니다. mysql npm을 사용하고 있습니다.


0

Node.js의 대량 삽입은 아래 코드를 사용하여 수행 할 수 있습니다. 이 작업을 위해 많은 블로그를 참조했습니다.

이 링크도 참조하십시오. https://www.technicalkeeda.com/nodejs-tutorials/insert-multiple-records-into-mysql-using-nodejs

작동 코드.

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

이것이 당신을 도울 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.