我有模型A和模型B. A has_and_belongs_to_many
Bs,反之亦然。
现在,我想在A中找到一个对象/实体,其中包含B内的某些对象(比如B1和B2)。我怎样才能在Rails中有效 ?我目前的解决方案是这样的:
A.all.select {|a| a.bs.sort == [B1, B2]}.first
它基本上遍历A中的所有对象,并检查它是否has_and_belongs_to
正确的Bs。这是非常低效的。有更好的方法吗?
答案 0 :(得分:2)
您可以使用嵌套的子查询来执行此操作,这是一个有效的解决方案,但不一定是高效的,因此您必须运行一些基准测试。
以下涉及在A
和B
之间的join_table上执行的三个嵌套查询。
您首先要确定B
或excluded_bs
以外的所有B1
的ID(称为B2
)。然后,您可以确定哪些A
与这些excluded_bs
有关系,并将其称为excluded_as
。不在A
中的所有excluded_as
都是我们想要的(称为included_as
)。一旦included_as
只查询A
表。
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
和B1
完全关系的所有B2
,但不包含任何其他关系。你可能能够稍微清理一下并提高效率,但它至少应该有效。
编辑:
糟糕!要修剪那些只有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)
答案 1 :(得分:1)
您可以过滤habtm关联:
A.joins(:bs).where("bs.id" => [B1, B2]).first
A.joins(:bs).where("bs.id" => [B1, B2]).all
要确保仅返回具有两个关联的项目,请使用
A.joins(:bs).where("bs.id" => [B1, B2]).group("as.id HAVING COUNT(bs.id) = 2")