ฉันจะทำการแทรกจำนวนมากใน mySQL โดยใช้ node.js ได้อย่างไร


123

เราจะแทรกจำนวนมากลงใน mySQL ได้อย่างไรหากใช้บางอย่างเช่น https://github.com/felixge/node-mysql


คุณมีปัญหาอะไร? คุณสามารถทำได้เช่นเดียวกับคำสั่ง sql หรือไม่? เพียงเริ่มคำสั่งถัดไปเมื่อก่อนหน้านี้เสร็จสมบูรณ์จนกว่าคุณจะแทรกข้อมูลทั้งหมด
Andrey Sidorov

3
ฉันรู้สึกว่าเม็ดมีดจำนวนมากเร็วกว่าเม็ดมีดเดี่ยวหลายเท่า
crickeys

ในระดับสายพวกเขาเหมือนกัน ไม่มี 'การแทรกจำนวนมาก' ในโปรโตคอล mysql
Andrey Sidorov

1
มีการแทรกหลายรายการใน mySQL คุณเพียงแค่ใช้คำหลัก VALUES dev.mysql.com/doc/refman/5.5/en/insert.htmlคำสั่ง INSERT ที่ใช้ไวยากรณ์ VALUES สามารถแทรกหลายแถว ในการดำเนินการนี้ให้รวมรายการค่าคอลัมน์หลายรายการโดยแต่ละรายการจะอยู่ภายในวงเล็บและคั่นด้วยเครื่องหมายจุลภาค ตัวอย่าง: 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 =?", [column, ID] ดังนั้นคอลัมน์จะขยายเป็นเครื่องหมายคำถามแรกและ ID ไปยังอันที่สอง
Selay

3
น่าเสียดายที่คำตอบนี้ใช้ไม่ได้สำหรับฉัน ฉันคัดลอกคำตอบของคุณตามความเป็นจริง แต่ไม่ประสบความสำเร็จ ฉันโพสต์คำถามอื่นในstackoverflow.com/questions/41170849/…
Ivan 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
ฉันชอบวิธีแก้ปัญหาของคุณ
โจ

วิธีนี้ใช้ได้ผลสำหรับฉัน! TY! POSTMAN: [{"textQuestionBuilderID": "5", "presidentID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "presidentID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "presidentID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "presidentID": "ABC123", "resultSelected ":" sfgh "}]
Brian

8

อุปกรณ์ประกอบฉากทั้งหมดสำหรับ Ragnar123 สำหรับคำตอบของเขา

ฉันแค่ต้องการขยายหลังจากคำถามที่ Josh Harington ถามเพื่อพูดคุยเกี่ยวกับ ID ที่แทรก

สิ่งเหล่านี้จะเรียงตามลำดับ ดูคำตอบนี้: การแทรกหลายแถว 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)

หวังว่านี่จะช่วยได้


เรารับประกันได้หรือไม่ว่าในกรณีของการแทรกพร้อมกันสภาพการแข่งขันจะไม่ผสมรหัสแทรก?
Purefan

1
@Purefan ตามการทดสอบของฉันใช่อย่างไรก็ตามใครจะรู้ว่าสิ่งนี้จะเปลี่ยนไป
thewormsterror

โปรดทราบว่าสิ่งนี้จะใช้ได้ก็ต่อเมื่อขนาดของขั้นตอน auto_increment อยู่ที่ค่าเดิมคือ 1 ดูdev.mysql.com/doc/refman/5.7/en/…
luksch

6

นี่คือสนิป "raw-copy-paste" อย่างรวดเร็วเพื่อพุชคอลัมน์ไฟล์ใน mysql ด้วย node.js> = 11

250k แถวในไม่กี่วินาที

'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

ฉันไม่รู้ว่าทำไมคุณถึงแยกมันออกเป็นชิ้น ๆ จนกว่าฉันจะลองโดยไม่ ในบางจุดส่วนแทรกของฉันมีขนาดใหญ่เกินกว่าที่เซิร์ฟเวอร์จะประมวลผลได้ทันท่วงทีและฉันได้รับข้อผิดพลาดของ EPIPE การแบ่งเม็ดมีดออกเป็นชิ้น ๆ ช่วยแก้ปัญหานั้นได้ :)
Kit Peters

4

ในกรณีที่จำเป็นนี่คือวิธีที่เราแก้ไขการแทรกอาร์เรย์

คำขอมาจากบุรุษไปรษณีย์ (คุณจะดูที่ "แขก")

 {
  "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 () {}) แม้ว่าตัวแปร values ​​จะเป็นอาร์เรย์ แต่เรายังมี ห่อด้วย []
Anh Nguyen

แพ็คเกจ node-mysql ปัจจุบันมีไวยากรณ์ที่แตกต่างกันโดยสิ้นเชิงเมื่อเทียบกับแพ็คเกจ mysql ลิงค์แพ็คเกจ node-mysql คือnpmjs.com/package/node-mysql mysql package link คือ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. เปลี่ยนแบบสอบถามจาก insert (a, b) เป็นค่า table1 (?) ==> insert (a, b) เป็น table1 values? . กล่าวคือ นำเครื่องหมายที่อยู่รอบ ๆ เครื่องหมายคำถามออก

หวังว่านี่จะช่วยได้ ฉันใช้ 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.