Nodejs: Batch insert of large number of rows into a database

batch-processing, database, node.js

Solution

I've found a solution that works for me, but I'm still interested in understanding how this technically works.

Reading the node-async docs I found a few functions to achieve this:

async.map //iterates over an array

async.each //iterates over an array in parallel

async.eachSeries //iterates over an array sequentially

async.eachLimit //iterates over an array in parallel with n (limit) parallel calls.

For instance:

var results = []; //still huge array
// "4" means, async will fire the iterator function up to 4 times in parallel
async.eachLimit(results,4,function(row,cb){
  var data = prepareMyData(row);
  db.InsertQuery(data,function(err, response)
  {
    if (!err)
    {
        cb(err,response);
    }
  }
},function(err,res)
{
    console.log('were done!');
});

Problem

I want to process a large number of records (>400k) in a batch and insert them into a database. I know how to iterate over an array with for() or underscore.each() and also I know how to insert a record into various (no)SQL databases asynchronously. That's not the problem - the problem is I can't figure a way to do both at the same time. The database distribution itself doesn't play a role here, the principle applies for any (NO)SQL database with an async interface. I'm looking for a pattern to solve the following problem: The loop approach: ``` var results = []; //imagine 100k objects here _.each(results,function(row){ var newObj = prepareMyData(row); db.InsertQuery(newObj,function(err,response) { if(!err) console.log('YAY, inserted successfully'); }); }); ``` This approach is obviously flawed. It kinda hammers the database with insert queries without waiting for a single one to finish. Speaking about MySQL adapters using a connection pool, you pretty soon run out of connections and the script fails. The recursion approach: ``` var results = []; //again, full of BIGDATA ;) var index = 0; var myRecursion = function() { var row = results[index]; var data = prepareMyData(row); db.InsertQuery(data,function(err, response) { if (!err) { console.log('YAY, inserted successfully!'); index++; //increment for the next recursive call of: if (index < results.length) myRecursion(); } } } myRecursion(); ``` While this approach works pretty well for small chunks of data (though it can be slow, but that's ok. the event loop can rest a while, waiting for the query to finish), it work doesn't for large arrays - too many recursions. I could write a batch insert easily in any other procedural language like PHP or so, but I don't want to. I want to solve this, asynchronously, in nodejs - for educational purposes. Any suggestions?

Original source