Overview
Mongoid の関連付けにより、モデル間の関係を作成できます。このガイドでは、参照された関連付けによって、一方のモデルが他方のモデルを参照する 2 つのモデル間の関係を作成する方法について説明します。 Mongoid は、次の参照される関連付けのタイプをサポートしています。
has_onehas_manybelongs_tohas_and_belongs_to_many
次のセクションでは、これらのそれぞれの関連付けタイプの使用方法について説明します。
が 1 つ
has_one マイクロを使用して、1 つのクラスで表されるドキュメントに、別の 子クラスによって表されるドキュメントも含まれていることを宣言できます。 次の例では、 Studioクラスに対する has_one の関係を持つ Bandクラスを作成します。
class Band include Mongoid::Document has_one :studio end
has_one 関連付けを宣言する場合、子クラスは親クラスを参照する belongs_to 関連付けも使用する必要があります。 次の例では、先行する Bandクラスで参照されている Studioクラスを示しています。
class Studio include Mongoid::Document belongs_to :band end
belongs_toマイクロの詳細については、「 が に属する 」セクションを参照してください。
次の例に示すように、検証を使用して、子クラスが親クラスに存在することを確認できます。
class Band include Mongoid::Document has_one :studio validates_presence_of :studio end
が多い
has_many マイクロを使用して、クラスによって表されるドキュメントに、別のクラスによって表される複数の子ドキュメントが含まれていることを宣言できます。 次の例では、 Membersクラスに対する has_many の関係を持つ Bandクラスを作成します。
class Band include Mongoid::Document has_many :members end
has_many 関連付けを宣言する場合、子クラスは親クラスを参照する belongs_to 関連付けも使用する必要があります。 次の例では、先行する Bandクラスで参照されている Memberクラスを示しています。
class Member include Mongoid::Document belongs_to :band end
マイクロの詳細については、 [ Belongs To ]belongs_to セクションを参照してください。
次の例に示すように、検証を使用して、子クラスが親クラスに存在することを確認できます。
class Band include Mongoid::Document has_many :members validates_presence_of :members end
Mongoid の検証の詳細については、「 検証ガイド 」を参照してください。
関連付け情報の検索
has_many 関連付けで any? メソッドを使用すると、データベースからドキュメントセット全体を取得せずに、関連付けにドキュメントが含まれているかどうかを判断できます。
次の例では、 any? メソッドを使用して、Bandクラスのドキュメントに Members ドキュメントが含まれているかどうかを判断します。
band = Band.first band.members.any?
次の例に示すように、any? メソッドをフィルターと併用して、指定された条件に一致するドキュメントを検索することもできます。
band = Band.first band.members.any? { |member| member.instrument == 'piano' }
any? メソッドにクラス名を指定すると、クラスの名前で結果をフィルタリングできます。 これは多態的な 関連付けに便利です。
class Drummer < Member end band = Band.first band.members.any?(Drummer)
注意
関連付けられているクラスのデータが Mongoid に読み込まれた後は、any? メソッドに対する後続の呼び出しでは、データベースはクエリされません。 代わりに、Mongoid はメモリにすでにロードされているデータを使用します。
また、exists? メソッドを呼び出して、関連付け内に永続化されたドキュメントがあるかどうかを確認することもできます。 exists? メソッドは常にデータベースをクエリし、データベースに保存されているドキュメントのみをチェックします。 exists? メソッドはフィルタリングを許可しておらず、引数を受け入れません。
次の例では、 exists? メソッドを使用して、Bandクラスに永続化された Members ドキュメントがあるかどうかを判断します。
band = Band.create! # Member is not persisted. band.members.build band.members.exists? # Outputs: false # Persist the member band.members.map(&:save!) band.members.exists? # Outputs: true
に属します
belongs_to マイクロを使用して、1 つのクラスによって表されるドキュメントが、別のクラスによって表されるドキュメントの子であることを宣言します。 デフォルトでは 、親クラスの _idフィールドは子クラスに保存されます。 次の例では、 Bandクラスへの belongs_to の関連付けを持つ Membersクラスを作成します。
class Members include Mongoid::Document belongs_to :band end
次の例に示すように、optional オプションを true に設定することで、Mongoid が関連付けられている親クラスの _id を保存せずにドキュメントをデータベースに永続化できるようにします。
class Members include Mongoid::Document belongs_to :band, optional: true end
Tip
アプリケーションの 構成設定 で belongs_to_required_by_default 構成オプションを false に設定することで、belongs_to 関連付けのデフォルトの動作をグローバルに変更して、親クラスを不要にすることができます。
親クラスで一致する has_one または has_many の関連付けを指定しなくても、子クラスで belongs_to の関連付けを指定できます。 そうすると、親クラスから子ドキュメントのフィールドにはアクセスできませんが、親の _idフィールドなど、子クラスに保存されている親フィールドにはアクセスできます。 次の例では、BandクラスはMembersクラスにアクセスできませんが、MembersクラスはBandクラス にアクセスできます。
class Band include Mongoid::Document end class Members include Mongoid::Document belongs_to :band end
明確にするために、次の例に示すように、親クラスに子クラスへの has_one または has_many の関連付けが含まれていないことを示す、inverse_of オプションを nil に設定できます。
class Band include Mongoid::Document end class Members include Mongoid::Document belongs_to :band, inverse_of: nil end
を持つ と が多数に属する
has_and_belongs_to_many マイクロを使用して、クラスモデルに別のクラスとの多対多の関係が含まれていることを宣言します。 多対多の関係では、1 つのクラス内の各ドキュメントを別のクラスの複数のドキュメントに関連付けることができます 。 次の例では、 Membersクラスへの has_and_belongs_to_many の関係を持つ Bandクラスを作成します。 Bandドキュメントは複数の Members ドキュメントを参照でき、Membersドキュメントは複数の Band ドキュメントを参照できます。
class Band include Mongoid::Document has_and_belongs_to_many :members end class Members include Mongoid::Document has_and_belongs_to_many :bands end
has_and_belongs_to_many の関連付けを宣言すると、両方のモデル インスタンスに関連付けられているドキュメントの _id 値のリストが保存されます。 関連するドキュメントの _id 値をモデル インスタンスの 1 つだけに保存するには、inverse_of オプションを nil に設定します。 次の例では、関連付けられているドキュメントの _id 値を Bandクラスのみに保存するように Mongoid に指示します。
class Band include Mongoid::Document has_and_belongs_to_many :tags, inverse_of: nil end class Tag include Mongoid::Document end
Tip
has_and_belongs_to_many の関連付けがあるドキュメントを更新すると、Mongoid は更新されたドキュメントの updated_atフィールドを設定しますが、関連付けられているドキュメントの updated_atフィールドは設定しません。
クエリ参照の関連付け
集計パイプラインを使用して、参照されている関連付け全体のドキュメントをクエリできます。 集計パイプラインと、複数のコレクションにわたるクエリを作成したり、指定した形式でデータを操作したりできます。 集計パイプライン の使用方法の詳細については、 集計ガイドを参照してください。
単純なクエリの場合は、関連付けを直接クエリできます。 コレクションを直接クエリする場合、コレクション自体にあるフィールドと値のみをクエリできます。 クエリ対象に関連付けられているコレクションを直接クエリすることはできません。
例、次の Band クラスと Tour クラスについて考えてみます。
class Band include Mongoid::Document has_many :tours field :name, type: String end class Tour include Mongoid::Document belongs_to :band field :year, type: Integer end
次の例では、 year の値が 2000 以上であるドキュメントを Tourクラスでクエリし、それらのドキュメントの band_id を保存します。 次に、それらの band_id 値を持つドキュメントを Bandクラスでクエリします。
band_ids = Tour.where(year: {'$gte' => 2000}).pluck(:band_id) bands = Band.find(band_ids)