如何使用node.js在MySQL中进行批量插入


123

如果使用https://github.com/felixge/node-mysql这样的内容,如何将大量插入MySQL中


你有什么问题?可以使用与一个sql命令相同的方式来执行此操作吗?上一个完成时,只需启动下一个命令,直到插入所有数据即可。
Andrey Sidorov 2012年

3
我的印象是,BULK刀片比许多单个刀片要快。
crickeys 2012年

在电线水平上,它们是相同的。mysql协议中没有“批量插入”
安德烈西多罗夫

1
在mySQL中有多个插入,您只需使用VALUES关键字。 dev.mysql.com/doc/refman/5.5/en/insert.html使用VALUES语法的INSERT语句可以插入多行。为此,请包括多个列值列表,每个列值括在括号内并用逗号分隔。示例:INSERT INTO tbl_name(a,b,c)VALUES(1,2,3),(4,5,6),(7,8,9);
曲棍球

Answers:


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()使用准备好的语句相同的保护?如果不是,在执行插入操作时是否可以利用准备好的语句?谢谢。
维格斯

2
是的,使用此方法可以转义值。我认为这是与准备好的语句相同的机制,它也在内部使用connection.escape()。
Ragnar123

7
这让我感到困惑。为什么数组必须是[[['a','b'],['c','d']]]而不是[['a','b'],['c','d ']]像文档中说的那样?
维克托里奥·贝拉2015年

12
Victorio Berra,这是因为最外面的数组通常是语句中匹配的一个问号,而不仅仅是插入中。例如,如果您有两个问号占位符,那么您将有[param1,param2]。说“ UPDATE Users?WHERE ID =?”,[列,ID]因此,列将扩展到第一个问号,ID扩展到第二个问号。
塞莱2015年

3
不幸的是,这个答案对我不起作用。我从字面上复制了您的答案,但没有成功。我在stackoverflow.com/questions/41170849/…
IvanPandžić16年

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!邮递员:[{“ 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的所有道具供他解答。

在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的对象数组中提取了值。)

希望这可以帮助。


我们是否保证在同时插入的情况下竞争条件不会混合插入ID?
Purefan '16

1
@Purefan根据我的测试,是的,但是谁知道这是否会改变。
thewormsterror

请注意,如果AUTO_INCREMENT步长是它的1.见原值这只会工作dev.mysql.com/doc/refman/5.7/en/...
luksch

6

这是一个快速的“原始复制粘贴”,可通过node.js> = 11推送到mysql中的文件列

在几秒钟内达到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,而没有任何括号。这样,可以在批量插入中自动处理列的数组。用它来分析M​​ySQL中数百兆的访问日志。
亚历克斯·帕卡

我不知道为什么要把它分成几块,直到我不加尝试。在某个时候,我的插入内容太大,服务器无法及时处理,并且出现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-mysqlRagnar。我正在使用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

与mysql软件包相比,当前的node-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. 将查询从insert(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);
  });

希望这会帮助你。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.