Mongooseを使って複数のMongoDBを1つのDBのように扱う方法
Tokyo Otaku ModeではNode.jsからMongoDBにアクセスするのにODMとしてMongooseを採用しています。
Mongoose(ODM)を利用するメリットとしては、
- collectionのSchema設計がコードに残る
- virtualなどデータ周りの機能がModelに集約できる
- populationが利用できる
などが上げられます。
どれもサービスを効率的に作る上で助かる機能ばかりですが、とくにpopulationは別ドキュメントのreference(_id
)を持っているだけで、自動的にドキュメントに展開してくれる強力な機能です。
一方で、DBロック回避の目的やある程度の規模になってDBを分割するようになると、別DBのcollectionをpopulateできないという問題がでてきます。
Mongooseの仕様上、特定DBへのconnectionとModel(collection)が密に結びついているため、参照元のModelと同じconnectionを持っていないと、参照先に辿りつけないからです。
これを回避するため、Tokyo Otaku ModeではMongooseのconnectionに少し手を入れてDB間のpopulationを実現しています。
まず簡単にpopulationの機能を説明します。
以下の様な、テキストが保存されたPostsドキュメントとそのテキストを投稿したユーザーが保存されたUsersドキュメントあるとします。
|
|
|
|
こういうドキュメント構造に対して、populationを指定して実行すると、
|
|
userが展開されて取得できます。
|
|
裏側では、populationで指定されたフィールド(user)のリファレンス先collection(Users)に接続してデータを取得・展開しているだけですが、自分自身と同じconnectionを利用するので、別DBのcollectionは未定義のModelと判断されてしまいます。
さて、では実際にどう解決しているのかコードベースで解説いたします。
設定情報
環境ごとの設定ファイルになります。
ModelがどのDBに存在するかのマッピングを設定するroutesと、それぞれの接続情報が書かれています。何も設定しないとmongodb1
DBに接続するようになっています。
|
|
コネクションマネージャ
上記設定情報を元に、どのModelをどのconnectionに結びつけるかを決定し、実際にコネクションを管理します。
肝は最初の接続時に接続先connectionとModel情報をマッピングしておき、Modelを呼び出す際に、対象のconnectionに書き換える点です。
|
|
各モデル
通常、mongoose.model
に名前とSchemaを渡すところをmanager.dispatch
に渡します。
|
|
|
|
最後に
このように、managerにconnectionの管理とModelのマッピング機能を一つにまとめ、各Modelでは特に接続先を意識せずにmongoose.model
をmanager.dispatch
に置き換えるだけで、分断されたDB間でもpopulationが利用できるようにしています。
DBの構成変更は設定ファイルを変更するだけでメンテナンスもしやすくなっています。
Tokyo Otaku ModeではNode.js/MongoDBを使い倒したい エンジニアを募集しています。
興味のある方はこちらからご応募ください。