Node.js で SQLite を扱う

Node.js で SQLite を簡単に扱える sqlite3 というパッケージがあったので紹介。

目次

パッケージのインストール

適当な作業ディレクトリを作って npm init などしておき、以下のコマンドで SQLite をインストールする。

$ npm install sqlite3 --save

インストール時にソースのビルドを行っているようで、手元では何やら警告が出た場合もあったのだが、とりあえずうまく使えていたので無視してしまった。

sqlite という名前のパッケージもあったが、コチラの進化系としてアナウンスされているのが sqlite3 であった。また、better-sqlite3 という各種チューニングされたパッケージもあったが、今回は使わない。

データの登録

まずはデータを登録してみる。以下のように insert.js を作ってみよう。

const sqlite = require('sqlite3').verbose();
const db = new sqlite.Database('example.sqlite');  // SQLite の DB ファイル名

// SQL を同期的に実行する
db.serialize(() => {
  // テーブルがなければ作成する
  db.run('CREATE TABLE IF NOT EXISTS user (name TEXT, age INTEGER)');
  
  // Prepared Statement でデータを挿入する
  const stmt = db.prepare('INSERT INTO user VALUES (?, ?)');
  stmt.run(['Foo', 25]);
  stmt.run(['Bar', 39]);
  stmt.run(['Baz', 31]);
  
  // prepare() で取得した Prepared Statement オブジェクトをクローズする。これをコールしないとエラーになる
  stmt.finalize();
});

db.close();

これをコマンドラインで

$ node insert.js

という風に実行すると、プロジェクトルートに example.sqlite ファイル (2行目で指定しているファイル) が生成される。これが SQLite の DB ファイルである。DB Browser for SQLite などの適当なビューアで開いてみると、3件のデータが登録されていることが分かるであろう。

データの取得

次に、登録したデータを取得してみる。以下のように select.js を作ってみよう。

const sqlite = require('sqlite3').verbose();
const db = new sqlite.Database('example.sqlite');

db.serialize(() => {
  db.each('SELECT * FROM user', (error, row) => {
    if(error) {
      console.error('Error!', error);
      return;
    }
    
    // カラムを指定してデータを表示する
    console.log(row.name + ' … ' + row.age);
  });
});

db.close();

これを

$ node select.js

というように実行すると、

$ node select.js
Foo … 25
Bar … 39
Baz … 31

と表示されるはずだ。

また、example.sqlite ファイルを削除してから呼んでみると、以下のようにエラーが表示されるはずだ。

$ node select.js
Error! { Error: SQLITE_ERROR: no such table: user
    at Error (native) errno: 1, code: 'SQLITE_ERROR' }

応用

公式の GitHub Wiki に API リファレンスがあるのだが、イマイチ分かりにくい。

自分なりに調べてみたことをメモしておく。

トランザクション管理

以下の API でトランザクションの開始、コミット、ロールバックができる。

db.exec('BEGIN TRANSACTION');
db.exec('COMMIT');
db.exec('ROLLBACK');

Prepared Statement の書き方

Prepared Statement の実行方法は複数の書き方がある。

// パラメータを引数に列挙していく書き方
db.run('UPDATE user SET name = ? WHERE id = ?', 'Bar', 2);

// パラメータを第2引数に配列で渡す書き方
db.run('UPDATE user SET name = ? WHERE id = ?', ['Bar', 2]);

// パラメータに名前を付けて連想配列で渡す書き方
db.run('UPDATE user SET name = $name WHERE id = $id', {
  $name: 'Bar'
  $id: 2
});

名前付きパラメータで許容されるのは :name@name$name の3種類だが、JavaScript 内で扱いやすいのは $name であろう。

また、? の後ろに数字を付けて、連想配列や配列で対応付けをしても実行できたりする。

db.run('UPDATE user SET name = ?2 WHERE id = ?1', {
  2: 'Bar',
  1: 2
});

db.run('UPDATE user SET name = ? WHERE id = ?2', ['Bar', 2]);

上の2つはどちらも同じ UPDATE 文になる。

一括取得

データを一括取得するには、db.each() ではなく db.all() を使うと良い。

db.all('SELECT * FROM user', (error, rows) => {
  if(error) {
    console.error('Error!', error);
    return;
  }
  
  console.log('Select All : ', rows);
});

このように書くと、以下のように配列でデータが取得できていることが分かる。

$ node select.js
Select All : [ { name: 'Foo', age: 25 },
  { name: 'Bar', age: 39 },
  { name: 'Baz', age: 31 } ]

以上

大規模な環境が必要ないのであれば、Node.js でサーバを立て、この sqlite3 で DB を構築する、といった使い方もできるであろう。サクッと作れて便利。