[JavaScript] SQLiteにCSVからのデータを入れたい

2015/03/13

こんにちは。きんくまです。
だいぶ暖かくなってきましたね。

さて、オリジナルのデータベースから吐き出されたCSVのデータがあって、そこから自分の開発用にSQLiteのデータを用意したくなりました。
それでどうやってやろうかなと思ってjsでやってみました。という感じのメモです。

使ったnodeのモジュールは以下のものです。

csv-parse
line-reader
sqlite3

4万件をデータをいれてみたけど、とりあえずうまく動いているみたいなので大丈夫かと思います。

コード

//設定 =========

//CSVのファイル名、同じ名称でxxxx.dbができあがる
var filePrefix = 'my_csv_file';

var csvPath = './csv/' + filePrefix + '.csv';
var databasePath = './db/' + filePrefix + '.db';

//Insertするたびコンソールに出力するか。出力しない方が速い
var insertLogEnable = false;

//==================


var parse = require('csv-parse');
var lineReader = require('line-reader');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(databasePath);

var count = 0;
var startTime;

function setupDatabase(callback){
    var stmt = "CREATE TABLE persons (name TEXT, age INTEGER)";
    db.run(stmt, callback);
}

function insertRow(rowArray, callback){
    var stmt = ["INSERT INTO persons VALUES ("];
    var maxIndex = rowArray.length - 1;
    rowArray.forEach(function(elem, index){
        stmt.push('?');
        if(index != maxIndex){
            stmt.push(",");
        }
    });
    stmt.push(')');
    db.run(stmt.join(''), rowArray, callback);
}

function loadCSV(){
    lineReader.open(csvPath, function(reader) {
        function readNextLine(){
            if (reader.hasNextLine()) {
              reader.nextLine(function(line) {
                parse(line, {}, function(err, output){
                    var row = output[0];
                    insertRow(row, function(err){
                    	if(err){
                    		console.log('line ' + count + ' Error! ' + row[0]);
                    		console.log(err);
                    	}else if(insertLogEnable){
                    		//insertするたびに呼ばれるコメント。出したい文言を出力する
                    		console.log('line ' + count + ' ' + row[0] + ' inserted');
                    	}
                        readNextLine();
                    });
                });
              });
          }else{
              db.close();
			  var lapse = (new Date()).getTime() - startTime.getTime();
			  lapse = lapse / 1000.0;
              console.log('total ' + count + ' insert complete! ' + lapse + 's');
          }
            count++;
        }
        readNextLine();
    });
}

setupDatabase(function(){
	startTime = new Date();
    loadCSV();
});

死のピラミッドがいくつか見られますが、自分用の開発ツールなのでキニシナイ!

たくさんの行数があるものは、1度に処理するのではなくて、1行ずつ読み込んでそのたびにDBに加える処理してあげれば問題ないみたい。
なので、line-readerというモジュールで1行ずつ読み込んでいます。

====

さすがにあのピラミッドはマズいので書き直した。

//設定 =========

//CSVのファイル名、同じ名称でxxxx.dbができあがる
var filePrefix = 'my_csv_file';

var csvPath = './csv/' + filePrefix + '.csv';
var databasePath = './db/' + filePrefix + '.db';

//Insertするたびコンソールに出力するか。出力しない方が速い
var insertLogEnable = false;

//==================

var parse = require('csv-parse');
var lineReader = require('line-reader');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(databasePath);

var count = 0;
var startTime;



function setupDatabase(callback){
    var stmt = "CREATE TABLE persons (name TEXT, age INTEGER)";
    db.run(stmt, callback);
}

     
function insertRow(rowArray, callback){
    var stmt = ["INSERT INTO persons VALUES ("];
    var maxIndex = rowArray.length - 1;
    rowArray.forEach(function(elem, index){
        stmt.push('?');
        if(index != maxIndex){
            stmt.push(",");
        }
    });
    stmt.push(')');
    db.run(stmt.join(''), rowArray, callback);
}

function parseCSVLine(line, reader){
	parse(line, {}, function(err, output){
		var row = output[0];
		insertRow(row, function(err){
			if(err){
				console.log('line ' + count + ' Error! ' + row[0]);
				console.log(err);
			}else if(insertLogEnable){
				console.log('line ' + count + ' ' + row[0] + ' inserted');
			}
			readNextCSVLine(reader);
		});
	});
}

function readNextCSVLine(reader){
	if (reader.hasNextLine()) {
		reader.nextLine(function(line) {
			parseCSVLine(line, reader);
		});
	}else{
		db.close();
		var lapse = (new Date()).getTime() - startTime.getTime();
		lapse = lapse / 1000.0;
		console.log('total ' + count + ' insert complete! ' + lapse + 's');
	}
	count++;
}

function loadCSV(){
    lineReader.open(csvPath, readNextCSVLine);
}

setupDatabase(function(){
	startTime = new Date();
    loadCSV();
});

==

余談なんだけど、SQLのstatementとqueryって何が違うのかって調べたらわかりやすく書いてあった。

>> Difference between a statement and a query in SQL

つまり、こんな感じかな。

StatementはDBの何らかの操作をするとき。(CRUDとかテーブルの構造作ったりとか)
Queryは何かの値を取得するとき(SELECT)のStatementの別名。DBの情報自体に変更はない。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る