2012-01-17 9 views
68

Come si farebbe un grosso inserto in MySQL se si utilizza qualcosa come https://github.com/felixge/node-mysqlCome faccio a fare un inserimento di massa in MySQL utilizzando node.js

+0

qual è il tuo problema? Puoi farlo allo stesso modo con un comando sql? Basta iniziare il comando successivo quando il precedente è stato completato fino a quando non hai inserito tutti i dati. –

+2

Ho avuto l'impressione che gli inserti BULK siano più veloci di molti singoli inserti. – crickeys

+0

a livello di filo sono uguali. Non esiste un 'bulk-insert' nel protocollo mysql –

risposta

153

inserimenti di massa sono possibili utilizzando array nidificato, vedere la github page

Gli array annidati vengono trasformati in elenchi raggruppati (per inserti collettivi), ad es. [['a', 'b'], ['c', 'd']] si trasforma in ('a', 'b'), ('c', 'd')

Basta inserisce un array nidificato di elementi.

Un esempio è dato in here

var mysql = require('node-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: values è un array di array avvolto in un array

[ [ [...], [...], [...] ] ] 
+1

Questo fornisce le stesse protezioni di 'conn.execute()' per usare le istruzioni preparate? In caso contrario, è possibile utilizzare istruzioni preparate quando si inseriscono gli inserti? Grazie. – Vigs

+0

Sì, i valori sono scappati con questo metodo. Penso che sia lo stesso meccanismo delle istruzioni preparate, che usa internamente anche connection.escape(). – Ragnar123

+3

Questo mi confonde. Perché l'array deve essere [[['a', 'b'], ['c', 'd']]] e non [['a', 'b'], ['c', 'd ']] come dice la documentazione? –

5

Tutti puntelli Ragnar123 per la sua risposta.

Volevo solo espanderlo dopo la domanda posta da Josh Harington per parlare degli ID inseriti.

Questi saranno sequenziali. Vedere questa risposta: Does a MySQL multi-row insert grab sequential autoincrement IDs?

Quindi si può semplicemente fare questo (noto quello che ho fatto con la 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); 
    }); 

(ho tirato i valori da una matrice di oggetti che ho chiamato persistentObjects.)

Spero che questo aiuti.

+0

abbiamo la garanzia che nel caso di inserimenti simultanei le condizioni di gara non si combinino con gli ID di inserimento? – Purefan

+1

@Purefan Secondo i miei test si, comunque chissà se questo cambierà mai. – thewormsterror

+0

Si noti che ciò funzionerà solo se la dimensione del passo auto_increment è sul valore originale di 1. Vedere http://dev.mysql.com/doc/refman/5.7/en/replication-options-master.html#sysvar_auto_increment_increment – luksch

1

Se la risposta di Ragnar non funziona per voi. Qui è probabilmente il motivo (in base alla mia esperienza) -

  1. non stavo usando node-mysql pacchetto come indicato mia Ragnar. Stavo usando il pacchetto mysql. Sono diversi (se non te ne sei accorto - proprio come me). Ma non sono sicuro che abbia qualcosa a che fare con il ? non funzionante, dal momento che sembra funzionare per molte persone che usano il pacchetto mysql.

  2. provare a utilizzare un variabile anziché ?

Di seguito ha lavorato per me -

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

Spero che questo aiuti qualcuno.

+0

Penso che potresti dimenticare di inserire [] in valori. È successo anche a me. Dovrebbe essere: conn.query (sql, [valori], function() {}) Invece di: conn.query (sql, values, function() {}) Nonostante la variabile valori sia un array , ma dobbiamo ancora completarlo con [] –

2

Nel caso in cui aveva bisogno ecco come abbiamo risolto inserto di matrice

richiesta proviene da postino (Si guarda "ospiti")

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

E come sceneggiato

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

Non riesco ancora a commentare, quindi invierò una risposta.

@ Ragnar123 risposta è corretta, ma vedo molte persone nei commenti dicendo che non funziona. Ho avuto lo stesso problema e sembra che tu abbia bisogno di avvolgere l'array a []

così

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

deve essere passato come [pars] nel metodo.

Spero che questo aiuti.

+1

Sì, per qualche ragione deve essere un array, una serie di array ... – Joe

2

Stavo cercando una risposta sull'inserimento di massa degli oggetti.

La risposta da Ragnar123 mi ha portato a fare questa funzione:

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

Speranza che aiuta!

0

Stavo avendo un problema simile. Ne stava solo inserendo uno dalla lista degli array. Ha funzionato dopo aver apportato le seguenti modifiche.

  1. Passato [parametri] al metodo di query.
  2. Modificata la query da insert (a, b) in valori table1 (?) ==> insert (a, b) in valori table1? . vale a dire. Rimossa la parestes attorno al punto interrogativo.

Spero che questo aiuti. Sto usando mysql npm.

Problemi correlati