3

我有一个模型 A 和一个模型 B。A has_and_belongs_to_manyBs,反之亦然。

现在,我想在 A 中找到一个对象/实体,该对象/实体具有 B 中的某些对象(比如 B1 和 B2)。我怎样才能在 Rails中有效地做到这一点?我目前的解决方案是这样的:

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

它基本上遍历A 中的所有对象并检查它是否has_and_belongs_to是正确的 B。那是非常低效的。有一个更好的方法吗?

4

2 回答 2

2

您可以使用嵌套子查询来做到这一点,这是一种可行的解决方案,但不一定是有效的解决方案,因此您必须运行一些基准测试。

以下涉及在A和之间的 join_table 上执行的三个嵌套查询B。您首先确定所有不是or的 id B(称为这些) 。然后,您确定哪些与这些有关系并调用它们。所有不在其中的 's正是我们想要的(称它们为)。一旦你刚刚查询了表。excluded_bsB1B2Aexcluded_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])

这应该为您提供与 和 有关系的所有' As ,但不与任何其他人有关系。您可能可以稍微清理一下并使其更有效率,但它至少应该可以工作。B1B2

编辑:

哎呀!要修剪那些只有B1orB2的部分,请尝试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

为确保只返回恰好具有两个关联的项目,请使用

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