情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

Node.jsでSQLite3を使用する

SQLite3を使用するにはnode-sqlite3パッケージのsqlite3モジュールを利用します。

データベースオブジェクト

SQLite3のデータベースオブジェクトはsqlite3.Databaseクラスのインスタンスとして表されます。

sqlite3.Databaseコンストラクタの第1引数にはファイル名を指定します。ただし、匿名のメモリデータベースを作成する場合には:memory:を指定し、匿名のディスクデータベースを作成する場合には空文字列を指定します。

データベースオブジェクトをインスタンス化すると対応するデータベースが開かれます。

データベースの処理においてエラーが発生した場合にはerrorイベントが発生します。このイベントのイベントハンドラの第1引数はエラーオブジェクトです。

データベースを閉じるにはsqlite3.Database.close関数を使用します。

SQL文の実行

データを取得しないSQL文を実行するにはsqlite3.Database.run関数を使用します。

第1引数にSQL文を指定します。

第2引数以降にSQL文のパラメータを指定します。パラメータは1つ1つを別々の引数として指定するか、配列として指定するか、オブジェクトとして指定します。

最後の引数にコールバック関数を指定します。この関数の第1引数はエラーオブジェクトです。


データを取得するSQL文を実行するには3つの方法があります。

  • sqlite3.Database.get関数
    SQL文を実行して得られた最初の行のみを取得します。
    引数はsqlite3.Database.run関数と同様です。ただし、コールバック関数の第2引数はSQL文を実行して得られた最初の行を表すオブジェクトです。

  • sqlite3.Database.all関数
    SQL文を実行して得られた全ての行を取得します。
    引数はsqlite3.Database.run関数と同様です。ただし、コールバック関数の第2引数はSQL文を実行して得られた全ての行を格納する配列です。

  • sqlite3.Database.each関数
    SQLを実行して得られた全ての行を1行ずつ取得します。
    引数はsqlite3.Database.run関数と同様です。ただし、コールバック関数の第2引数はSQL文を実行して得られたそれぞれの行を表すオブジェクトであり、コールバック関数はSQL文を実行して得られた全ての行に対して1回ずつ呼び出されます。

実行モード

実行モードをバーバスにするにはsqlite3.verbose関数を使用します。

バーバスにすると長いスタックトレースが生成されるようになります。ただし、これはデバッグのための機能であり、パフォーマンスが悪化するためプロダクション時には使用すべきではありません。

実行モードを直列にするにはsqlite3.Database.serialize関数を使用します。

直列にすると別のSQL文が実行中である場合、新たなSQL文を実行しようとした場合にはそのSQL文はキューに格納され、前のSQL文の実行が全て完了するまで実行されません。つまり、この実行モードではSQL文を1つずつ順番に実行していきます。

実行モードを並列にするにはsqlite3.Database.parallelize関数を使用します。

並列にすると別のSQL文が実行中であっても、新たなSQL文を実行しようとした場合にはすぐに実行されます。つまり、この実行モードではSQL文を複数個同時に実行します。

なお、sqlite3.Database.close関数は排他実行モードで実行されます。つまり、全てのSQL文の実行が完了するまで待機します。

サンプルコード1

メモリデータベースの使用例です。

sqlite3.js

var sqlite3 = require('sqlite3');

sqlite3.verbose();
var db = new sqlite3.Database(':memory:');
db.serialize();
db.on('error', function (err) {
    console.error(err);
    process.exit(1);
});

db.run('CREATE TABLE IF NOT EXISTS sample (info TEXT)');
for (var i = 0; i < 10; i++) {
    db.run('INSERT INTO sample VALUES (?)', 'i = ' + i);
}

db.each('SELECT rowid AS id, info FROM sample', function (err, row) {
    console.log(row.id + ': ' + row.info);
});

db.close();

使用パッケージ

  • node-sqlite3
    npm install sqlite3でインストールします。

実行結果

C:\work\node>node sqlite3.js
1: i = 0
2: i = 1
3: i = 2
4: i = 3
5: i = 4
6: i = 5
7: i = 6
8: i = 7
9: i = 8
10: i = 9

サンプルコード2

ディスクデータベースの使用例です。

コマンドライン引数として与えられたCSVファイル(タブ区切りなので正確にはTSVファイルと言うべきかもしれません)を読み込み、変換を行い、データベースに格納し、標準出力に出力します。

CSVデータのパースや変換の詳細な方法に関しては下の記事を参照してください。

sqlite3-csv.js

var sqlite3 = require('sqlite3');
var fs = require('fs');
var csvParse = require('csv-parse');
var streamTransform = require('stream-transform');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

sqlite3.verbose();
var db = new sqlite3.Database('english.db');
db.serialize();
db.on('error', function (err) {
    console.error(err);
    process.exit(1);
});

db.run('CREATE TABLE IF NOT EXISTS word (word TEXT PRIMARY KEY, meanings TEXT NOT NULL, level_alc TEXT NOT NULL, level_weblio TEXT NOT NULL)');

var rs = null;
try {
    rs = fs.createReadStream(process.argv[2], 'utf-8');
    rs.on('error', function (err) {
        console.error(err);
        db.close();
        process.exit(1);
    });
}
catch (err) {
    console.error(err);
    db.close();
    process.exit(1);
}

var parser = csvParse({ delimiter: '\t' });
parser.on('error', function (err) {
    console.error(err);
    db.close();
    process.exit(1);
});

var transformer = streamTransform(function (data) {
    var after = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i] != '') {
            after.push(data[i]);
        }
    }
    if (after.length == 4) {
        return after;
    }
    else {
        console.error('this is corrupted data.');
        return null;
    }
});
transformer.on('data', function (data) {
    db.run('INSERT INTO word VALUES ($word, $meanings, $level_alc, $level_weblio)', {
        $word: data[2], 
        $meanings: data[3], 
        $level_alc: data[0], 
        $level_weblio: data[1]
    }, function (err) {
        if (err) {
            if (err.code == 'SQLITE_CONSTRAINT' && err.message == 'SQLITE_CONSTRAINT: UNIQUE constraint failed: word.word') {
                console.error('this item is already registered: ' + data[2]);
            }
            else {
                console.error(err);
                process.exit(1);
            }
        }
    });
});
transformer.on('end', function (data) {
    db.each('SELECT word, meanings, level_alc, level_weblio FROM word', function (err, row) {
        console.log(row.word + ': ' + row.level_alc + ' ' + row.level_weblio + ' ' + row.meanings);
    });
    db.close();
});
transformer.on('error', function (err) {
    console.error(err);
    process.exit(1);
});

rs.pipe(parser).pipe(transformer);

使用パッケージ

実行結果

C:\work\node>node sqlite3-csv.js english.csv
reading: 3 1 測定値
style: 2 1 ~と呼ぶ、様式
due: 3 2 ~することになっている、期限が来て、正当な
ankle: 3 3 足首
discipline: 4 3 訓練、規律、分野、学科
extraordinary: 4 3 異常な
joint: 3 3 接合(部)、関節、いかがわしい場所、共同の
virtue: 4 3 美徳、効力
bundle: 5 4 ~を束ねる、束
deceive: 4 4 ~をだます
reproduce: 5 4 ~を複製する
rip: 6 4 ~を引き裂く
substitute: 4 4 ~を代わりに用いる、~を置換する、代用品、代用の
cashier: 6 5 現金出納係、レジ係
envy: 4 5 ~をうらやむ、うらやましさ
mouthful: 6 5 口いっぱい、正しい言葉
reap: 6 5 ~を収穫する、~を得る
refresh: 5 5 ~の元気を回復させる
refreshment: 6 5 元気回復、飲食物、軽食
deceit: 6 6 詐欺

関連

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-Node.js