Node.js で使えそうな軽量 NoSQL ライブラリを調べる
Node.js でちょっとしたアプリを開発していて、PostgreSQL とか MySQL とかいう DB を用意するのは大仰かな、という時に、SQLite を選定することはまぁありがちだろう。
しかし、それよりもさらにもう少しお手軽に、インストールが不要な・楽なライブラリは何かないかな、つーか RDBMS ほどガッチリした型がないモノもあるんだよなー、とか思って、軽量な NoSQL ライブラリを調べてみた。
目次
UnQLite
UnQLite は、SQLite に近い思想で作られている、シングル DB ファイルで管理される NoSQL ライブラリ。なんて読むんだろう、うんこらいと?w
C 言語ベースで作られているのだが、Node.js から操作するラッパーの npm パッケージがメンテされておらず、Node.js からの利用は難しい。
また、そもそもローカルでの UnQLite 単独の動作も上手くいかなかったので、今回はドッグフーディングできず。
- UnQLite - An Embeddable NoSQL Database Engine
- symisc/unqlite: An Embedded NoSQL, Transactional Database Engine
TingoDB
TingoDB は、NoSQL で知られる MongoDB と互換性があるという、Node.js ベースのライブラリ。ちんごでーびー?w
$ npm install -S tingodb
試しに以下のような Node.js スクリプトを書いてみた。
const DB = require('tingodb')().Db;
// 引数で指定した名前のディレクトリを用意しておくこと
const db = new DB('./tingodb-db', {});
// Collection (Table みたいなモノ) を選択する・コレが `db` で指定したディレクトリ配下にファイルとして作られる
const collection = db.collection('hello-world-collection');
// Collection に Document (レコードみたいなモノ) を書き込む
collection.insert(
[{ hello: 'World 1' }, { hello: 'World 2' }],
{ w: 1 }, // Primary に書き込みが完了したら成功とする、デフォルトオプション
(insertError, result) => {
if(insertError) return console.error('Insert Error', insertError);
console.log('Insert Result', result);
// 条件を指定して Document を検索・取得する
collection.findOne({ hello: 'World 2' }, (findError, item) => {
if(findError) return console.error('Find Error', findError);
console.log('Find Result', item);
});
}
);
実行してみる。
$ node ./tingodb.js
Insert Result [
{ hello: 'World 1', _id: ObjectID { id: 2 } },
{ hello: 'World 2', _id: ObjectID { id: 3 } }
]
Find Result { hello: 'World 2', _id: ObjectID { id: 3 } }
すると、次のようなファイルが生成されていた。
./tingodb-db/hello-world-collection
{"k":"0000000078","o":"0000000048","v":"001"}
{"_id":2,"_uid":2,"_dt":1630979090746,"_s":"4db1f9e54aeb4202e72f33276616f874"}
{"hello":"World 1","_id":{"$wrap":"$oid","v":2}}
{"k":"0000000078","o":"0000000048","v":"001"}
{"_id":3,"_uid":3,"_dt":1630979090748,"_s":"2f62c9a076c6455b0d4154c968c58c21"}
{"hello":"World 2","_id":{"$wrap":"$oid","v":3}}
拡張子はないが JSON チックな形式で記述されており、テキストエディタで開ける。メタ情報とデータが2行で1セットになっている感じ。雰囲気は JSON Lines っぽい。
自分は MongoDB に詳しくないのだが、データを JSON チックなテキストファイルで管理できるので扱いやすいかも。MongoDB のパッケージと互換性を保つためなのか、コールバック形式で記述するのがちょいと面倒かしら。
NeDB
NeDB は、TingoDB よりももう少しライトに使えそうなライブラリ。データはまさに JSON Lines 形式で管理される。
- louischatriot/nedb: The JavaScript Database, for Node.js, nw.js, electron and the browser
- NeDB を使ってみた - Qiita
$ npm install -S nedb
前述の TingoDB とほとんど同じような Insert・Select をやってみる。
const Datastore = require('nedb');
// 引数で指定した名前のディレクトリ・ファイルがなければ自動的に作成される
// 引数で Collection (Table みたいなモノ) 名を指定する・コレがファイルとして作られる
const collection = new Datastore({ filename: './nedb-db/hello-world-collection', autoload: true });
// Collection に Document (レコードみたいなモノ) を書き込む
collection.insert(
[{ hello: 'World 1' }, { hello: 'World 2' }],
(insertError, result) => {
if(insertError) return console.error('Insert Error', insertError);
console.log('Insert Result', result);
// 条件を指定して Document を検索・取得する
collection.findOne({ hello: 'World 2' }, (findError, item) => {
if(findError) return console.error('Find Error', findError);
console.log('Find Result', item);
});
}
);
実行するとこんな感じ。メタデータとなる _id
の持ち方が TingoDB とは違う。
$ node ./nedb.js
Insert Result [
{ hello: 'World 1', _id: 'ji9uXbxP92l42coh' },
{ hello: 'World 2', _id: '0VwBfnDfSuHa1JIm' }
]
Find Result { hello: 'World 2', _id: '0VwBfnDfSuHa1JIm' }
生成された DB ファイルはテキストファイルとして開ける。JSON Lines っぽい感じで、1行が1レコード (1 Document) となっている。
./nedb-db/hello-world-collection
{"hello":"World 1","_id":"ji9uXbxP92l42coh"}
{"hello":"World 2","_id":"0VwBfnDfSuHa1JIm"}
dby : DBYaml
dby は、YAML ファイルでデータを管理するライブラリ。Go 言語製で、Node.js (npm) 向けのラッパーはなさそうだが、面白そうだったので紹介のみ。
試してないヤツ
その他試していないのだが、以下はいずれも JSON ファイルとしてデータを管理してくれそうなライブラリ。サンプルコードを見るに、使用感は NeDB や TingoDB に似ている感じ。
- 参考 : javascript — Node.jsで使用する軽量Javascript DB
- Persistence
- nStore
- levelup
- node-dirty
- LocallyDB
- UeberDB
- jaguarDB (Archived)
どれを使うか
UnQLite は C 言語ベースなので、環境を選ばず使えそうかなーとは思うのだが、自分の環境では上手く使えなかったので惜しいなーと。
それ以外は、DB とするファイルに JSON や YAML といった形式を使うライブラリが多かった。テキストベースで扱いやすいし、配列の入れ子なども出来て NoSQL 的なデータの持ち方が容易なので、さもありなん。
- JSON ベースだと、ダブルクォートやブレース記号が多発するので、ファイルの可読性がちょい下がりがち。一方で、改行やインデントを省いて容量を削減したり、JS の世界ではそのまま連想配列として扱えるので、Node.js 上で扱う場合は親和性は高い。
- YAML の場合、JSON よりはファイルの可読性が高いだろう。ただし、(JSON 記法を混ぜない場合) 改行やインデントをサボれないので、ファイルサイズはちょっと大きくなりがち。JS 界隈ではパースして読み込む必要があるため、あまり表立って使用されないが、Go 言語などのプラットフォームで開発する場合はもう少し親和性も高そうだ。
今回ドッグフーディングした TingoDB と NeDB はよく似ている。結局 JSON ファイルで管理するので、ファイル I/O 性能に左右され、ライブラリとしての性能は大差ないかなと思う。いずれもコールバック関数で処理を記述していくタイプで、コーディングスタイルも大きく違わないかしら。大きな違いは「MongoDB の API と互換性があるかどうか」で、TingoDB は互換性があるので、「本番環境では MongoDB を使うつもり」のような要件があるのであれば、TingoDB が良いだろう。そうでなければ、MongoDB の API などを意識せず手軽に書ける NeDB を使うのが良いと思う。