« Mongoidの限界について | トップページ | MongoDBでのリレーションのパターン »

2011年11月27日 (日)

Mongorilla: Object Document Mapper for MongoDB

Mongorillaについて

Mongoidの弱点を克服するために作成したObject Document Mapper.
名前の由来は、Mongoと娘の好きな動物のgorillaを掛けあわせた。

インストール

gem install mongorilla

ソース
github

長所

  1. 今のところ、わずか300行ちょっとの小ささ。
  2. シングルサーバ、Master/Slave、ReplicaSetに対応。
  3. 単純な処理はMongoidと変わらず、複雑な処理も対応。
  4. クエリ発行時に接続失敗しても、指定回数リトライできる。
  5. findクエリに対してMasterとSlaveのどちらを参照するか指定できる。

短所

  1. リレーション関連は自分で管理する必要がある。
  2. 各フィールドの型も自分で整合性を保証する必要がある。

sample

require 'mongorilla'
# クラス名をunderscore化+複数形にしたcollectionが作成される
class User
  # クラス名+ Fieldsの定数に使用するフィールドをsymbolで定義
  UserFields = [:_id,:name,:password,:logs,:log_count]
  # Mongorillaを使うことを宣言
  include Mongorilla::Document
end
#アプリ起動時1回のみ呼び出す必要(設定ファイルに基いてDBに接続している)
Mongorilla::Collection.build(File.expand_path("../config.yml",__FILE__))
#ユーザデータをDBに登録し、登録したレコードを呼び出す
user = User.create(:name => "morita",:password => "pass")
#非同期で作成したい場合
User.create({:name => "morita",:password => "pass"},{:safe => false})
#複数ユーザ同時に作成したい場合
users = User.create([{:name => "morita",:password => "pass"},{:name => "yoshida",:password => "hello"}])
#IDで検索する場合 1オブジェクトのみ返る
u = User.find(user.id)
#属性で検索する場合 条件に一致したオブジェクトすべてがArrayで返る
us = User.find({:name => "morita"})
#オプションをつける。 :master => trueのみ独自(master DBから検索)。
#それ以外はmongo driverに等しい。
us = User.find({:name => "morita"},{:master => true,:limit => 3})
#件数を調べる。(find.countだとレコードをすべてObjectに変換した後、countしてしまうため)
count = User.count({:name => "morita"})
#属性の変更 DBにはsaveを実行するまで更新されない。 
u.name = "mora"
#属性の変更 DBにはsaveを実行するまで更新されない。
u.push("logs","oooo")
#属性の変更 DBにはsaveを実行するまで更新されない。p u.logs => ["oooo","aaa"]
u.push("logs","aaa")
#属性の変更 DBにはsaveを実行するまで更新されない。p u.log_count => 2
u.inc("log_count",2)
#上記の変更がDBに反映される(デフォルトは同期)
u.save
#属性の変更 DBにはsaveを実行するまで更新されない。p u.log_count => 1
u.inc("log_count",-1)
#条件を指定して更新。この場合は条件を満たさないため失敗
ret = u.save({:log_count => {"$gt" => 10}})
#false
p ret
# 2 失敗した場合は、元のデータに戻される
p u.log_count
# $pullの実行 ただしpullの場合はオブジェクトに反映されない(複雑だから。) p u.logs => ["oooo","aaa"]
u.pull("logs","oooo")
# 上記に合わせて、件数を減らす
u.inc("log_count",-1)
# RELOADの指定は、レコードの更新が成功した場合に、更新したレコードをDBから取り出して、
# オブジェクトの内容を更新する。$pullを使用した場合はオブジェクトとDBのレコードの間に
# 不整合ができるため、行うほうがいい。RELOAD以外は、SYNC(デフォルト)、ASYNC(非同期)がある
ret = u.save({:log_count => {"$gt" => 1}},Mongorilla::Document::RELOAD)
# pullをしてreloadしたことにより、"oooo"が取り除かれた。["aaa"] 
p u.logs

設定ファイル

Mongorilla::Collection.buildに渡す設定ファイル(yaml形式)のフォーマット

Single Serverの場合

host: localhost #任意
port: 27017     #任意
database: dev   #必須

Master/Slaveの場合

host: localhost     #必須
port: 27017         #必須
database: dev       #必須
slaves:             #必須
  - host: localhost #必須
    port: 27018     #必須


Replica Setの場合

hosts:
  - - localhost #HOST
    - 27017     #PORT
  - - localhost
    - 27018
  - - localhost
    - 27019
database: dev

内部実装について

Mongorilla::Documentをinclude指定された際に、指定されたフィールドごとにgetterとsetterを動的に作成している。
getterはメソッド呼びだし時にinitialize時に渡されたMongoのレコード(@docに保存)に対してフィールド名でアクセスした結果を返している。
setterは@changesに@changes["$set"][フィールド名] = 変更された内容をセットして、@docの内容を更新している。
saveを呼び出した時は、@changesの内容を用いてupdateしている。
複雑な更新をしたい場合は、Obj#changesで@changesを取得して変更し、@docの内容を更新する。
フィールドにセットするデータをチェックしたい場合は、def フィールド名= のメソッドをオーバーライドする。
リレーションの管理方法は、また今度。

|

« Mongoidの限界について | トップページ | MongoDBでのリレーションのパターン »

MongoDB」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/68673/53346203

この記事へのトラックバック一覧です: Mongorilla: Object Document Mapper for MongoDB :

« Mongoidの限界について | トップページ | MongoDBでのリレーションのパターン »