LoginSignup
21
8

More than 5 years have passed since last update.

embeds_* 🆚 has_*どっちを選ぶ!?

Posted at

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 OneHas Oneの違いはデータの持ち方です。

  • Embeds One
    parentのデータの中にchildrenのデータが入っています。そのため、parentからchildrenのデータを取りたいとき、別のクエリーが必要ないです(処理時間が少ない)
  • Has One
    parentのデータの中にchildrenのデータが入っていません。そのため、parentからchildrenのデータを取りたいとき、別のクエリーが必要です。

p.s.: embeds-manyhas-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_manyhas_manyのどちらを使いますか?

場合によって違います。
仕様が決まらないと、どちらを使うか選べません。
なので私は、以下の二つのケースを考えてから決めることにしています

:point_up:質問1. parentとchildrenを一緒に使うケースが多いですか?
- もし多かったらembeds_*を使った方が良いです。
 - 逆に、少なかったら、has_*を使った方が良いです。詳細

:point_up:質問2.parentがなくなると、childrenが存在する意味がなくなるか?
 - もしchildrenの存在する意味がまだあるなら、has_*を使った方が良いです。
 - 逆に、childrenの存在する意味がもうなくなるなら、embeds_*を使った方が良いです。

2つの質問を考えてもまだ決められない時は
has_*を使う場合の、クエリーコストを考えたり、
embeds_*を使う場合の、重複されるデータ量のことを考えます。詳細

embeds_* :

  • メリット:
    • childrenのデータを取得するスピードが早い
    • n+1 問題が起こりません
  • デメリット:
    • 集計、分析が難しい。ドキュメントに直接アクセスすることができないから。
    • ネストのデータは管理しにくい
    • 重複するデータが増える可能性が高い
    • ドキュメントのリミットがありますので増え続けるようなデータをembeds_*にしたら注意しないといけない。詳細

has_* :

  • メリット:
    • 集計、分析が比較的簡単です
    • 正規化(normalized data model)
  • デメリット:
    • childrenのデータを取得する場合、クエリーが必要です。
    • n+1 問題に気を付けないといけない

3. サンプル(実際に考えてみる)

  1. 記事とタグはembeds_、has_
  • 質問1を答える:

    • 記事を取得するたびに、タグを取得するケースが多発しそうな時、embeds_*が候補に上がります。
    • 記事のデータだけ取得するケースが多い場合、has_*でも大丈夫だと思います
  • 質問2を答える:

    • 記事を削除して、タグの存在する意味がなくなることはないので、has_*を使います。

なので僕はhas_*にします。

2.PostとCommentはembeds_、has_

  • 質問1を答える:
    • SNSの場合、Postを取得するたびに、commentも取得します。embeds_*で大丈夫です
    • comment数を数えたい、commentの意味を分析したい、like数を数えたい。この場合は、has_*もよさそうです。
  • 質問2を答える
    • Postを削除すると、commentの意味がなくなってしまいます。embeds_*を使う方がいいです。

なのでembeds_*にします。

3.他のは「記事とアイキャッチ」、「人とアドレス」

21
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
8