なんとなく思いつきでmongodbを触ってみた。
手元の環境はMaxOSX10.10で、mongodbのバージョンはv2.6.6です。
まずはmongodbのインストール。brewでインストールできる。
$ brew install mongodb
試しにサーバプロセスを手動で起動してみる。
ログが標準出力に垂れ流しになるので、別にターミナル上げてやった方がよい。
$ mkdir -p /tmp/mongo $ mongod --dbpath /tmp/mongo
dbpathの場所にファイルがいろいろできる。何も指定しないとデフォルトは/data/dbにできる。
クライアントのCLIはmongoコマンドで起動する。
$ mongo MongoDB shell version: 2.6.6 connecting to: test >
稼働確認でfooというdbを作って適当にJSONオブジェクトを突っ込んでみる。
> use foo switched to db foo > db.foo.save({text:"hello mongodb.", type:"message"}) WriteResult({ "nInserted" : 1 }) > db.foo.save({text:"hoge", type:"message"}) WriteResult({ "nInserted" : 1 }) > db.foo.find() { "_id" : ObjectId("549a97030c7fbf2751eaa215"), "text" : "hello mongodb.", "type" : "message" } { "_id" : ObjectId("549a97200c7fbf2751eaa216"), "text" : "hoge", "type" : "message" } > exit bye
動いってるっぽい。
ここからはnodeからの呼び出しをやってみる。
今回書いたコードの全体は以下に置いておきました。
https://github.com/minamijoyo/mongo-example
元にするのは前に書いたsocket.ioのチャットサンプルを改造してメッセージをDBに保存するようにしてみる。
$ git clone git@github.com:minamijoyo/chat-example.git mongo-example $ cd mongo-example $ npm install
mongodbをnodeから触るのはmongooseというライブラリが有名っぽいです。
$ npm install mongoose --save
package.jsonはこんなかんじになった。
{ "name": "mongo-example", "version": "0.0.1", "description": "mongodb example", "dependencies": { "express": "^4.10.2", "mongoose": "^3.8.21", "socket.io": "^1.2.1" } }
で、サーバサイドのメインindex.jsは以下のようにした。
var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var mongoose = require('mongoose'); var db = mongoose.connect('mongodb://localhost/chatlog'); var ChatSchema = new mongoose.Schema({ message: {type: String} }); var ChatLog = db.model('chatlog', ChatSchema); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); io.on('connection', function(socket){ ChatLog.find(function(err,items){ if(err){ console.log(err); return; } if(items.length > 0){ for(var i=0; i<items.length; i++){ socket.emit('chat message',items[i].message); } } }); socket.on('chat message', function(msg){ var chatlog = new ChatLog({message:msg}); chatlog.save(function(err){ if(err){ console.log(err); return; } io.emit('chat message', msg); }); }); }); http.listen(3000, function(){ console.log('listening on *:3000'); });
ポイント補足。
最初にmongooseを読み込んで、connectでDBのURLを指定して接続する。localhostの後ろのchatlogというのがDB名になる。
var mongoose = require('mongoose'); var db = mongoose.connect('mongodb://localhost/chatlog');
次にSchemaの定義で、JSON形式でテーブルレイアウトを定義する。データベースによって用語がバラバラで混乱するけど、まぁレコードの型とか定義するみたいな理解でだいたい合ってると思う。
var ChatSchema = new mongoose.Schema({ message: {type: String} });
で、db.modelにスキーマ渡してjavascriptから触れるオブジェクトを作る。第1引数に「chatlog」と指定している名前の複数形の「chatlogs」というコレクション(いわゆるテーブル)がmongodb上にできる。なんで指定した名前に勝手にs付けるのか気持ち悪い。
var ChatLog = db.model('chatlog', ChatSchema);
で、あとは前回のsocketのイベントに検索と保存を実装する。
まずはsocket接続してきたときに処理。
io.on('connection', function(socket){ ChatLog.find(function(err,items){ if(err){ console.log(err); return; } if(items.length > 0){ for(var i=0; i<items.length; i++){ socket.emit('chat message',items[i].message); } } });
モデルのChatLogのfind()で検索できる。検索結果はitemsのオブジェクトの配列で返ってくるので、オブジェクトからmessageを取り出してクライアントに返す。
次にsocketのメッセージ送ってきたときの処理。
socket.on('chat message', function(msg){ var chatlog = new ChatLog({message:msg}); chatlog.save(function(err){ if(err){ console.log(err); return; } io.emit('chat message', msg); });
JSONのオブジェクトにしてモデルを作って、save()で保存する。元々あったio.emitのsocketのブロードキャストはどっちでもよいけどsaveが成功したときだけにした。
使ってみて雑感。
トランザクションとかないNoSQLなのでミッションクリティカルなところには使いづらいけど、こんなかんじで、JSONのオブジェクトをお手軽に永続化できるかんじなのでWebサービスとかのバックエンドでゆるふわなかんじでJSONと合わせて使うのにはよさそう。
参考