Как выполнить массовую вставку в mySQL с помощью node.js

123

Как сделать массовую вставку в mySQL, если использовать что-то вроде https://github.com/felixge/node-mysql

crickeys
источник
в чем дело? Можете ли вы сделать это так же, как с помощью одной команды sql? Просто запускайте следующую команду, когда предыдущая завершена, пока не вставите все данные.
Андрей Сидоров
3
У меня сложилось впечатление, что BULK Inserts быстрее, чем многие одиночные пластины.
crickeys
на уровне проводов они такие же. В протоколе mysql нет «массовой вставки»
Андрей Сидоров
1
в mySQL есть несколько вставок, вы просто используете ключевое слово VALUES. dev.mysql.com/doc/refman/5.5/en/insert.html Операторы INSERT, использующие синтаксис VALUES, могут вставлять несколько строк. Для этого включите несколько списков значений столбцов, каждый из которых заключен в круглые скобки и разделен запятыми. Пример: INSERT INTO имя_таблицы (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 для массовой вставки

Ragnar123
источник
2
Обеспечивает ли это такую ​​же защиту, как и conn.execute()при использовании подготовленных операторов? Если нет, можно ли использовать подготовленные операторы при вставке? Спасибо.
Vigs
2
Да, с помощью этого метода значения экранируются. Я думаю, что это тот же механизм, что и подготовленные операторы, который также внутренне использует connection.escape ().
Ragnar123
7
Меня это сбивает с толку. Почему массив должен быть [[['a', 'b'], ['c', 'd']]], а не [['a', 'b'], ['c', 'd ']] как написано в документации?
Викторио Берра,
12
Викторио Берра, это потому, что самый внешний массив - это тот, который соответствует вопросительным знакам в операторе в целом, а не только во вставке. Например, если у вас есть два заполнителя вопросительного знака, тогда у вас будет [param1, param2]. Скажите «ОБНОВИТЬ пользователей? ГДЕ ID =?», [Столбцы, ID] Таким образом, столбцы будут расширены до первого вопросительного знака, а ID - до второго.
Селай
3
К сожалению, этот ответ не работает для меня. Я буквально скопировал ваш ответ, но безуспешно. Я разместил еще один вопрос на stackoverflow.com/questions/41170849/…
Иван Панджич
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]в метод.

Codendaal
источник
6
Да, по какой-то причине это должен быть массив, массив массивов ...
Джо
Кроме того, похоже , что это требует единственного числа ?вместо того , ??чтобы получить правильную группировку.
Федерико
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) => {...}
);
SnobOfTheGolfClub
источник
3
Мне нравится ваше решение
Джо
Это решение сработало для меня! TY! POSTMAN: [{"textQuestionBuilderID": "5", "schemeID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "6", "schemeID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "7", "schemeID": "ABC123", "resultSelected": "sfgh"}, {"textQuestionBuilderID": "8", "schemeID": "ABC123", "resultSelected ":" sfgh "}]
Брайан
8

Выражаю благодарность Рагнару123 за его ответ.

Я просто хотел расширить его после вопроса, заданного Джошем Харингтоном, о вставленных идентификаторах.

Они будут последовательными. См. Этот ответ: захватывает ли многострочная вставка MySQL последовательные идентификаторы автоинкремента?

Следовательно, вы можете просто сделать это (обратите внимание, что я сделал с 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.)

Надеюсь это поможет.

thewormsterror
источник
Гарантируем ли мы, что в случае одновременных вставок условие гонки не будет смешивать идентификаторы вставок?
Purefan
1
@Purefan Согласно моим тестам, да, но кто знает, изменится ли это когда-нибудь.
thewormsterror
Обратите внимание, что это будет работать только в случае , если размер шага auto_increment на его первоначальной стоимости 1. См dev.mysql.com/doc/refman/5.7/en/...
luksch
6

Это быстрое "необработанное копирование-вставка", предназначенное для вставки столбца файла в mysql с помощью node.js> = 11

250 тыс. Строк за несколько секунд

'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
Я не понимал, почему вы разбиваете это на куски, пока не попробовал без него. В какой-то момент моя вставка стала слишком большой для своевременной обработки сервером, и я получил ошибку EPIPE. Это исправляет разбиение вставки на куски. :)
Кит Петерс
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. Я использовал mysqlpackage. Они разные (если не заметили - такие же, как я). Но я не уверен, связано ли это с тем, что он ?не работает, поскольку, похоже, это сработало для многих людей, использующих 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
Агнель Вишал,
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.

user1998289
источник
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);
  });

Надеюсь, что это поможет вам.

Yadhu
источник