基礎から学ぶNode.js

第4回 Node.jsアプリケーションとMongoDBの連携

この記事を読むのに必要な時間:およそ 2.5 分

はじめに

前回から,いよいよNode.jsを使ったWebアプリケーションを作成しはじめました。前回はデータを保存および読み出す処理がなかったので,今回はデータベースとの連携を実装したいと思います。使うのはMongoDBです。リレーショナルデータベースに対して,MongoDBはドキュメント指向データベースという位置づけです。JSON構造をそのまま保存できるため,Node.jsとの親和性も高いです。簡単に導入でき,日本語ドキュメントもあるので,初めてでもすんなり使えると思います。

MongoDBのセットアップ

MongoDBのサイトから,OSごとに用意されたアーカイブをダウンロードして展開してください。展開したフォルダの直下にあるbinディレクトリ内にコマンド群があるため,これらを使って操作します。サーバデーモンとなるのがmongodで,クライアントとなるのがmongoになります。

まず適当にデータファイルを置く空ディレクトリを用意してください。そこを指定してmongodを実行するだけサーバが起動します。

mongod --nojournal --noprealloc --dbpath <データディレクトリパス>

なお,MongoDBは基本的に最初から巨大なファイルを用意することで,パフォーマンスを上げる方針で作られているため,デフォルトで起動すると,何もデータを入れてなくてもGB単位でディスク領域を占有します。今回は単に開発で使用するので,ジャーナル機構やデータファイルを先に確保する機構は,無効化しています。フォアグランドで起動するので,CTRL + Cで終了できます。

Mongooseを使ってNode.jsからMongoDBを利用

MongoDBをnodeから利用するには,node-mongodb-nativeという標準ドライバモジュールがあります。今回はそれをさらにO/Rマッパーのように利用できるモジュールMongooseを使って,MongoDBを使ってみます。

前回作成したfirstappのディレクトリで関連モジュールをインストールします。

cd firstapp
npm install mongoose

として利用するモジュールをインストールします。

モデルの実装

続いてmodel.jsというファイル名で,下記のコードを作成定義します。

var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/firstapp');

function validator(v) {
  return v.length > 0;
}

var Post = new mongoose.Schema({
    text   : { type: String, validate: [validator, "Empty Error"] }
  , created: { type: Date, default: Date.now }
});

exports.Post = db.model('Post', Post);

まず,mongooseモジュールの読み込みです。次にconnectメソッドで,localhostで稼働するMongoDBのfirstappデータベースに接続します。

投稿データをPostというモデルで定義します。Postモデルのスキーマは,textという文字列フィールドと,dateという日付型でデフォルトは現在日時が入るフィールドを定義します。またtextフィールドには,「文字列長が0より大きいか」バリデート関数を指定しています。

modelメソッドは,「Post」という名前でPostモデルのスキーマを登録しています。MongoDB上では,「posts」というコレクション(RDBでいうテーブルに該当)で管理されます。Mongooseによって,小文字かつ複数形に変換された名前となります。戻り値がデータアクセスモデルとなるので,それをexportsに渡して,外から使えるようにします。

アプリケーションの修正

前回作成したroutes/main.jsを修正して,Postモデルを利用するようにします。

var model = require('../model');
var Post = model.Post;

exports.index = function(req, res){
  Post.find({}, function(err, items){
      res.render('index', { title: 'Entry List', items: items })
    });
};

exports.form = function(req, res){
  res.render('form', { title: 'New Entry' })
};

exports.create = function(req, res){
  var newPost = new Post(req.body);
  newPost.save(function(err){
     if (err) {
       console.log(err);
       res.redirect('back');
     } else {
       res.redirect('/');
     }
    });
};

はじめに,model.jsを読み込みます。さらにPostモデルを直接利用できるように変数宣言しなおします。

ルートパスにアクセスしたときのリスト表示では,findメソッドを使って,postsコレクションのドキュメントを全て取得しコールバック関数function(err, items)で,結果を処理します。Findメソッドの第1引数は条件(SQLでいうwhere句)を指定できます。この場合全てなので空のオブジェクトにしています。コールバックの方は,第1引数にクエリ失敗時のerrオブジェクト,第2引数に正常時の結果が入ります。よって,errオブジェクトの有無で失敗と成功の切り分けをします。

/createに対する処理は,まずリクエストbodyの中身をそのままPostモデルのコンストラクタに渡して,一致するフィールド(ここではtext)の値をセットしつつ生成しています。そしてsaveメソッドを呼んでコレクションに書き込んでいます。コールバック関数function(err)で,成功か失敗かを判断し,エラー時は前の画面に戻しています。前の画面のURLは,Referrerヘッダを利用してExpressが自動で処理しています。設定した文字列長確認のバリデートに不適合だった場合もここでエラーとなります。

動作確認

以上で実装は完了です。アプリケーションを起動して,

node app.js

ブラウザから「http://localhost:3000/」にアクセスしてみましょう。

「New Entry」リンクからフォームにテキストを入力してPostしていくと,どんどんリストの項目が増えていくことがわかると思います。テキストを空でPostすると,コンソールに出力されるログでバリデートエラーが確認できます。

最後にMongoDBのシェルから実際のデータを確認してみます。mongodコマンドと同じ場所にあるmongoコマンド別のプロンプトから実行してください。まずshow dbsと命令すると,存在するデータベースの一覧が出ます。「use <データベース名>」で操作するデータベースを指定します。さらに「show collections」で,データベース内のコレクションの一覧が出ます。「db.<コレクション名>.find()」でコレクションの中身を表示します。

$ mongo
MongoDB shell version: 2.0.6
connecting to: test
> show dbs
firstapp	0.078125GB
local	(empty)
> use firstapp
switched to db firstapp
> show collections
posts
system.indexes
> db.posts.find()
{ "text" : "最初の投稿です。", "_id" : ObjectId("4ff96c7d7f12ede516000001"), "created" : ISODate("2012-07-08T11:18:21.466Z") }
{ "text" : "2番目の投稿です。", "_id" : ObjectId("4ff96c8b7f12ede516000003"), "created" : ISODate("2012-07-08T11:18:35.904Z") }
{ "text" : "3番目の投稿です。", "_id" : ObjectId("4ff96ca37f12ede516000006"), "created" : ISODate("2012-07-08T11:18:59.385Z") }

_idというのは,MongoDBのドキュメントにおける主キーのようなもので,未指定だと自動で割り当てられます。また特にセットしていない作成日時createdもスキーマに定義したとおり,追加時点での現在日時が入っています。

最後に

今回は,Mongooseを使ってMongoDBに,前回のアプリケーションを接続してみました。シンプルではありますが,非常に少ないコードで実装が終わってしまったと思います。この手軽さがNode.jsの魅力の1つだと筆者は思っています。次回以降は,様々なクラウドサービス上でこのアプリケーションをデプロイして動かしていきたいと思います。

著者プロフィール

高橋俊光(たかはしとしみつ)

ティルフィン合同会社 代表。

メーカー企業でパッケージソフト開発などに携わった後,ティルフィン合同会社を設立しフリーエンジニアとして,RIAやスマートモバイルアプリとサーバーサイドと広い分野で開発に従事。iOSアプリ トレンドトピック,Newstrushをリリースしている。

コメント

コメントの記入