node.jsアプリで heroku から mongoLab に mongodb で繋ぐ方法

node.jsを使って作成したチャットアプリ(DevHub)を mongodb に対応した時の覚書。

やりたかったこと

  • 一つの DB を複数の Model から利用したい
  • Model からはそれぞれのテーブル名を定義してデータ保持したい
  • Model 間の依存関係を減らしたいので Model はそれぞれライブラリ化したい
  • 各Model は DB 名を意識したくない。知っているのは自分のテーブル名のみ

heroku側の設定

・heroku から mongolab を使うには heroku 上で addon を verify しておく。クレジットカード番号などが必要
・アドオンをインストールする

$ heroku addons:add mongolab:starter

package.json に mongodb を定義

  • mongodb は最新では heroku 上でのインストールでエラーになったので、とりあえず 0.9.8 では上手くいった。(2012/03/28 時点)
{
  "name": "DevHub",
  "version": "0.0.1",
  "dependencies": {
    "express": "~> 2.5.1"
  , "commander": "~> 0.5.2"
  , "ejs": "~> 0.4.3"
  , "socket.io": "~> 0.9.2"
  , "mongodb": "0.9.8"
  }
}
  • npm install する。

mongodb への接続ロジック

  • DBへの接続の仕方は、ローカルでは open() で良いが、heroku では connect() を使う
  • ローカルか heroku の判定は process.env.MONGOLAB_URI が存在するかどうか
  • ローカルの場合は open() のコールバックで db を取得する
  • heroku の場合は connect() のコールバックで db を取得する
  • 受け取った db を使いたいオブジェクトに設定してあげると、db 経由で db.collection() などが叩けるようになる。

コードイメージ

  • まずは db を取得する為のライブラリを作成。(lib/mongo_builder.js)
var mongo = require('mongodb');

module.exports.ready = function(db_name, callback){
  if ( process.env.MONGOLAB_URI ){
    // herokuの場合の処理
    mongo.connect(process.env.MONGOLAB_URI, {}, function(error, db){
      callback(db);
    });
  }else{
    // localの場合の処理
    new mongo.Db(db_name, new mongo.Server('127.0.0.1', mongo.Connection.DEFAULT_PORT, {}), {}).open(function(err,db){
      callback(db);
    });
  }
};
  • 呼び出し側のコード。ready()で取得した db を利用者(Model)に渡す。
var mongo_builder = require('./lib/mongo_builder');
var chat_log = require('./lib/chat_log');

mongo_builder.ready(db_name, function(db){
  chat_log.set_db(db);
});
  • 利用者では受け取った db に対してテーブル名を指定しつつ書き込みなどを行う。(lib/chat_log.js)
var db;
var table_name = 'chat_log';

// db を受け取ってローカルに保持
module.exports.set_db = function(current_db){
  db = current_db;
};

// チャットメッセージ保存処理
module.exports.add = function(data){
  db.collection(table_name, function(err, collection) {
    collection.save( data, function(){} );
  });
};
  • このような作りだと、利用者が増えても ready() のコールバックに設定することで同一 db の利用が容易にできる。
var mongo_builder = require('./lib/mongo_builder');
var chat_log = require('./lib/chat_log');
var text_log = require('./lib/text_log');  // 利用者を追加

mongo_builder.ready(db_name, function(db){
  chat_log.set_db(db);
  text_log.set_db(db);  // 利用者へ db 設定処理を追加
});

おまけ

  • ちなみに、heroku 上で日本時間にするには以下を叩く。
$ heroku config:add TZ=Asia/Tokyo