Node.jsとMongoDBの連携例としてチャットのサンプルアプリを作成した。このデモを見ながらNode.jsとMongoDBの連携方法を学んでいこう。
前回と同様GitHubにコードをアップしているので、アプリを試したい場合は、git cloneでソースをダウンロードして実行してみよう。
$ git clone git://github.com/coppieee/node-memo-demo.git $ cd node-chat-demo $ npm install $ node app
アプリ起動前にmongodでデータベースを起動させよう。
$ mongod
http://localhost:3000/でアプリにアクセスできる。createボタンがあるので、クリックしてメモを作成してみよう。ドラッグでメモの移動もできる。Socket.IOも使用し、リアルタイムに更新しているので、複数ブラウザを開いて確認してみよう。基本的な構成はREABLOでの文章作成と同じように、1文字打つたびに、Socket.IOでテキスト情報を送る実装になっている。
このアプリでは、メモのテキストデータと、メモの座標をMongoDBに保存している。ブラウザをリロードしても、アプリを再起動しても、前のメモが表示されることを確認すれば、きちんとデータベースに保存されているのが分かる。
MongoDBは各プログラミング言語で使用するためのドライバが用意されている。
http://www.mongodb.org/display/DOCS/Node.js
Node.jsでMongoDBを使用する場合は、MongoDBの公式ドライバのmongodbを使用するか、そのオブジェクトラッパーライブラリのMongooseを使用するのがよい。デモではMongooseを使用して実装している。
MongooseはMongoDBシェルと同じようなAPIがあるのだが、MongoDBにはないスキーマを使用してデータの操作を行うところが大きく違う。スキーマというのは、データの型宣言のようなものだ。MongoDB自体はJSONならどんな値でも挿入でき、型や値のチェックなどは自分で行わないといけないのだが、スキーマを使用すると、その型や値チェックをしてくれるので、間違ったデータが混入してしまうのを防ぐことができる。
var mongoose = require('mongoose'); //localhostのnode_memo_demoのデータベースに接続。 var db = mongoose.connect('mongodb://localhost/node_memo_demo'); //メモのスキーマを宣言。 var MemoSchema = new mongoose.Schema({ text:{type:String} ,position:{ left:Number ,top:Number } }); //スキーマからモデルを生成。 var Memo = db.model('memo',MemoSchema);
デモでは、テキストと座標を持つMemoSchemaを宣言している。データの処理は、スキーマから生成したModelを基に行うことになる。
Memo.find(function(err,items){ if(err){console.log(err);} //接続したユーザーにメモのデータを送る。 socket.emit('create',items); });
上の例ではMemo.find()ですべてのメモのデータを取得し、Socket.IOを使用してクライアントにデータを送信している。モデルにはfind()やsave()などMongoシェルと似たような名前の関数が定義されているが、データをコールバックで受け取るなど、微妙に使い勝手が違うので注意しておこう。
デモでは、createボタンを押したときに、データを新規作成している。データの作成はnew Memo()で、モデルのインスタンスを作成し、save()でデータベースに保存している。new Memo()の引数には、Schemaで宣言した型のオブジェクトを入れる。
socket.on('create',function(memoData){ //モデルからインスタンス作成 var memo = new Memo(memoData); //データベースに保存。 memo.save(function(err){ if(err){ return; } socket.broadcast.json.emit('create',[memo]); socket.emit('create',[memo]); }); });
データの更新にはfindOne()でメモデータを取得し、値を変更し、save()することによって、更新する。findOne()はデータ1つだけ取得するメソッドだ。条件に_idが一致しているメモを指定している。
socket.on('update-text',function(data){ Memo.findOne({_id:data._id},function(err,memo){ if(err || memo === null){return;} memo.text = data.text; memo.save(); socket.broadcast.json.emit('update-text',data); }); });
削除は更新と同じように、findOne()で取得し、remove()で削除する。
socket.on('remove',function(data){ Memo.findOne({_id:data._id},function(err,memo){ if(err || memo === null){return;} memo.remove(); socket.broadcast.json.emit('remove',data); }); });
デモでは、保存、更新、削除のトリガーとしてSocket.IOのイベントをクライアントから受信して実行している。変更の流れとして、クライアント側で変更が行われたときに、Socket.IOでサーバにイベントを送信し、MongoDBのデータを更新、その更新情報を他のクライアントへSocket.IOでブロードキャストしているといった感じだ。
クライアント側の処理としては、直接MongoDBを触るわけではないので、前回のチャットデモと同じようにSocket.IOを使用して実装している。
前回のチャットアプリとの違いは、サーバ側のデータを変数として保持するか、データベースに保持するか程度の違いで、MongooseのAPIの使い勝手がよいおかげで、簡単にデータを永続化することができた。このデモアプリも、メモの幅を保存したり、メモの表示順を工夫したり、色や文字サイズを変更したりいろいろ改良点が見つかる。アイデア次第で追加できるが、実装自体は今回まで説明したExpressとSocket.IOとMongooseさえ使えこなせれば大抵のことはできるはずだ。
Mongooseの使い方をもっと知りたい人はドキュメントを眺めればいいと思う。
Copyright © ITmedia, Inc. All Rights Reserved.