1. 定義
Mongodbホームページにリレーションの定義が書いてあります。
- Embeds One
Embeds One
One to one relationships where the children are embedded in the parent document are defined using Mongoid’s embeds_one and embedded_in macros.
- Has One
Has One
One to one relationships where the children are referenced in the parent document are defined using Mongoid’s has_one and belongs_to macros.
Embeds One
とHas One
の違いはデータの持ち方です。
-
Embeds One
parentのデータの中にchildrenのデータが入っています。そのため、parentからchildrenのデータを取りたいとき、別のクエリーが必要ないです(処理時間が少ない) -
Has One
parentのデータの中にchildrenのデータが入っていません。そのため、parentからchildrenのデータを取りたいとき、別のクエリーが必要です。
p.s.: embeds-manyとhas-manyも上に書いた違いがあります。
2.どれが良いか?
Mongodbホームページの事例を見ましょう!
例1:
class Band
include Mongoid::Document
has_many :albums, dependent: :delete
end
例2:
class Band
include Mongoid::Document
embeds_many :albums
end
両方はBandとAlbumの関係を定義しています。
embeds_many
とhas_many
のどちらを使いますか?
場合によって違います。
仕様が決まらないと、どちらを使うか選べません。
なので私は、以下の二つのケースを考えてから決めることにしています
質問1. parentとchildrenを一緒に使うケースが多いですか?
- もし多かったら
embeds_*
を使った方が良いです。
- 逆に、少なかったら、has_*
を使った方が良いです。詳細
質問2.parentがなくなると、childrenが存在する意味がなくなるか?
- もしchildrenの存在する意味がまだあるなら、has_*
を使った方が良いです。
- 逆に、childrenの存在する意味がもうなくなるなら、embeds_*
を使った方が良いです。
2つの質問を考えてもまだ決められない時は
has_*
を使う場合の、クエリーコストを考えたり、
embeds_*
を使う場合の、重複されるデータ量のことを考えます。詳細
embeds_*
:
- メリット:
- childrenのデータを取得するスピードが早い
- n+1 問題が起こりません
- デメリット:
- 集計、分析が難しい。ドキュメントに直接アクセスすることができないから。
- ネストのデータは管理しにくい
- 重複するデータが増える可能性が高い
- ドキュメントのリミットがありますので増え続けるようなデータを
embeds_*
にしたら注意しないといけない。詳細
has_*
:
- メリット:
- 集計、分析が比較的簡単です
- 正規化(normalized data model)
- デメリット:
- childrenのデータを取得する場合、クエリーが必要です。
- n+1 問題に気を付けないといけない
3. サンプル(実際に考えてみる)
- 記事とタグはembeds_、has_?
-
質問1を答える:
- 記事を取得するたびに、タグを取得するケースが多発しそうな時、
embeds_*
が候補に上がります。 - 記事のデータだけ取得するケースが多い場合、
has_*
でも大丈夫だと思います
- 記事を取得するたびに、タグを取得するケースが多発しそうな時、
-
質問2を答える:
- 記事を削除して、タグの存在する意味がなくなることはないので、
has_*
を使います。
- 記事を削除して、タグの存在する意味がなくなることはないので、
なので僕はhas_*
にします。
2.PostとCommentはembeds_、has_?
- 質問1を答える:
- SNSの場合、Postを取得するたびに、commentも取得します。
embeds_*
で大丈夫です - comment数を数えたい、commentの意味を分析したい、like数を数えたい。この場合は、
has_*
もよさそうです。
- SNSの場合、Postを取得するたびに、commentも取得します。
- 質問2を答える
- Postを削除すると、commentの意味がなくなってしまいます。
embeds_*
を使う方がいいです。
- Postを削除すると、commentの意味がなくなってしまいます。
なのでembeds_*
にします。
3.他のは「記事とアイキャッチ」、「人とアドレス」