3

モデルAとモデルBhas_and_belongs_to_manyがあります。ABs、またはその逆です。

ここで、B内の特定のオブジェクト(たとえば、B1とB2)にhas_and_belongs_するA内のオブジェクト/エンティティを見つけたいと思います。Rails内でこれを効率的に行うにはどうすればよいですか?私の現在の解決策は次のようなものです:

A.all.select {|a| a.bs.sort == [B1, B2]}.first

基本的に、A内のすべてのhas_and_belongs_toオブジェクトを反復処理し、それが正しいBであるかどうかをチェックします。それは非常に非効率的です。これを行うためのより良い方法はありますか?

4

2 に答える 2

2

これは、ネストされたサブクエリを使用して実行できます。これは実用的なソリューションですが、必ずしも効率的なソリューションではないため、いくつかのベンチマークを実行する必要があります。

A以下は、との間のjoin_tableで実行される3つのネストされたクエリを含みますB。最初に、またはのいずれでもないすべてのID B(これらを呼び出しますexcluded_bs)を決定します。次に、これらと関係があるものを判別し、それらを呼び出します。含まれていないすべての'は、まさに私たちが望むものです(それらを呼び出します)。テーブルをクエリした後。B1B2Aexcluded_bsexcluded_asAexcluded_asincluded_asincluded_asA

excluded_bs = %(SELECT B_id FROM join_table WHERE B_id NOT IN (:included_bs))
excluded_as = %(SELECT A_id FROM join_table WHERE B_id IN (#{excluded_bs}))
included_as = %(SELECT A_id FROM join_table WHERE A_id NOT IN (#{excluded_as}))

A.where("id IN (included_as)", :included_bs => [B1.id, B2.id])

これにより、正確にAととの関係にあるすべての'が得られますが、他のとは関係がありません。これを少しクリーンアップしてより効率的にすることができるかもしれませんが、少なくとも機能するはずです。B1B2

編集:

おっと!B1またはのいずれかのみを持つものを削除するにはB2、を試してくださいGROUP BY。最後のサブクエリをに変更します

included_as = %(SELECT A_id, COUNT(*) as Total FROM join_table WHERE A_id NOT IN (#{excluded_as}) GROUP BY A_id HAVING Total = :count)

との主なクエリ

Bs = [B1, B2]
A.where("id IN (SELECT A_id FROM (#{included_as}))", :included_bs => Bs.map(&:id), :count => Bs.count)
于 2012-10-09T20:54:44.817 に答える
1

habtmアソシエーションでフィルタリングできます。

A.joins(:bs).where("bs.id" => [B1, B2]).first

A.joins(:bs).where("bs.id" => [B1, B2]).all

関連付けが2つだけのアイテムのみが返されるようにするには、次を使用します。

A.joins(:bs).where("bs.id" => [B1, B2]).group("as.id HAVING COUNT(bs.id) = 2")
于 2012-10-09T20:22:42.447 に答える