« Mongorilla: Object Document Mapper for MongoDB | トップページ | Mongorillaでリレーション管理 »

2011年12月13日 (火)

MongoDBでのリレーションのパターン

1対1の外部リレーション

embedの機能があるMongoDBで1対1の外部リレーションを使いたい場合というのは、そんなにないと思います。 しいて挙げるなら、あまり参照しないがデータサイズが大きいため、毎回読み込むのは避けたい場合ぐらい。 ただ、その場合でもfind時に必要なフィールドのみを取得できるオプション があり、それを使えば1対1で外部リレーションさせた場合と同じ効果が得ら れます。

1対多で他Documentとのリレーション

ログ等無限にどんどん増えるデータは、embedには向かないため、外部リレーションの関係になります。また細かい条件で検索したいレコードも 外部リレーションの1対多となります。例えば、10個以上20個未満のアイテムを探したいと思い、 find({:item.num => {"$gte" => 10,"$lte" => 20}})としても、1レコード全体を対象にするため、下記のレコードがHitしてしまいます。
{:item => [{:num => 5,:name => "りんご"},{:num => 25,:name => "みかん"}]}

1対1の内部リレーション

Atomicに扱いたいものの、直接のAttributeにしたくはないような レコードの場合。FiledをHashにして管理します。

1対多の内部リレーション

無限に増えそうもないデータ(持ち物情報等)は、embedにすることで、 Atomicに更新ができ、クエリも1回でデータを取得できます。
フィールドがArrayで値をHash形式で持つパターンとフィールドがHashで値もHash形式にするパターンとがあります。

フィールドがArrayのパターン

indexが貼りやすい反面、配列のデータの更新と追加が同時にできません。
例えば {name:"takeshi",age: 35, children: [{name: "takeru" ,age: 18}]}の レコードに対し、name:"takeru"のnumを19に変更すると同時に{name: "yui",num: 2}の レコードを追加といったことがatomicにできません。
indexは簡単で、[[children.name,Mongo::ASCENDING],[children.age,Mongo::DESCENDING]] を貼ることでfind({:children.name => "takeru",:children.age => 18})のような検索にindexを使います。
更新はchildren.0.ageのように添字を使って更新するため、削除があるようなレコードには あまり向いていません。他のプロセスが削除を行なった場合、添字で指定したレコードが 違うレコードを指す可能性があるためです。ただしArrayの内、1つのレコードのみ更新したい場合は、update({:children.name => "takeru"},{"children.$.age" => 19})のように検索条件で一致したレコードの添字の変わりに$が使えます。
削除は$pullを使いますが、一致するレコードが複数件存在する場合は、一致するものすべて削除されてしまうため、一致するレコード1件のみ削除したい場合は、$unsetで一致する レコードをnullにした後、$pullでnullのレコードを削除するという2段階踏む必要があります。

フィールドがHashの場合

レコードの更新の追加がatomicにできるのに対し、indexが各項目に対して作成する必要があります。 Hashの場合は、{name: "takeshi,items: {りんご: 1}}というレコードの値を2にすると同時 に{みかん: 1}のレコード追加が同時にAtomicできます。 ただし、indexは[["items.りんご",Mongo::ASCENDING],["items.みかん",Mongo::ASCENDING]] のように、アイテムの種類が増えればその度にindexを作成する必要があります。 削除は、$unsetを使用します。

まとめ

1対多のEmbedをArrayにするかHashにするかはよく悩みます。
基本的には、削除がなく、レコードの更新と追加が同時に必要にならないレコードであれば Arrayにし、削除があったり、レコードの更新と追加が同時に必要な場合はHashにするといいと思います。
ただ、indexの兼ね合いもあり、削除があっても論理削除をすることによって、 Arrayでも更新の不整合を防ぐことができます。
長くなったので、Mongorillaを使ったリレーションの管理は次回。

|

« Mongorilla: Object Document Mapper for MongoDB | トップページ | Mongorillaでリレーション管理 »

MongoDB」カテゴリの記事

コメント

コメントを書く



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




トラックバック

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

この記事へのトラックバック一覧です: MongoDBでのリレーションのパターン:

« Mongorilla: Object Document Mapper for MongoDB | トップページ | Mongorillaでリレーション管理 »