HABTM找到“AND”连接,而不是“OR”

我有两个模型,与HABTM相关联(实际上使用has_many:两端的连接,以及连接表)。 我需要检索与两个ModelB的BOTH相关联的所有ModelAs。 我不希望ModelB_1的所有ModelAs都与ModelB_2的所有ModelAs连接在一起。 我真的想要所有与BOTH ModelB_1和ModelB_2相关的ModelAs。 它不仅限于2个ModelB,最多可能有50个ModelB,因此必须进行扩展。

我可以使用各种类比来描述问题,我认为比前一段更好地描述了我的问题:

* Find all books that were written by all 3 authors together. * Find all movies that had the following 4 actors in them. * Find all blog posts that belonged to BOTH the Rails and Ruby categories for each post. * Find all users that had all 5 of the following tags: funny, thirsty, smart, thoughtful, and quick. (silly example!) * Find all people that have worked in both San Francisco AND San Jose AND New York AND Paris in their lifetimes. 

我已经想到了实现这一目标的各种方法,但它们的效率非常低,而且非常不受欢迎。

比如说上面的最后一个,你可以做一些事情,比如查询每个城市的所有人,然后找到每个arrays中存在的每个数组中的项目。 这是至少5个查询,这些查询的所有数据都转移回应用程序,然后应用程序必须将所有5个数组进行密集比较(循环丰富!)。 这很讨厌,对吗?

另一种可能的解决方案是将查找链接在彼此之上,这基本上与上面相同,但不会消除多个查询和处理。 此外,如果您有用户提交的复选框或值可能高达50个选项,您将如何动态化链? 看起来很脏。 你需要一个循环。 而且,这将加剧搜索持续时间。

显然,如果可能的话,我们希望让数据库为我们执行此操作,因此,人们向我建议我只是放入多个条件。不幸的是,您通常只能与HABTM进行OR。

我遇到的另一个解决方案是使用搜索引擎,如sphinx或UltraSphinx。 对于我的特殊情况,我觉得这有点矫枉过正,我宁愿避免它。 我仍然觉得应该有一个解决方案,让用户为任意数量的ModelB制作查询并找到所有ModelAs。

你怎么解决这个问题?

你可以这样做:

  1. 从ModelA构建一个查询,加入ModelB(通过连接模型),过滤具有您正在寻找的值之一的ModelB,即将它们放入OR(即where ModelB = 'ModelB_1' or ModelB = 'ModelB_2' )。 使用此查询,结果集将具有多个“ModelA”行,每个ModelB条件满足一行

  2. 按条件将组添加到您需要的ModelA列上的查询(如果您愿意,甚至可以添加所有这些列)。 每行的count( )等于满足的ModelB条件的数量*。

  3. 添加’having’条件只选择count(*)等于你需要满足的ModelB条件数的行

例:

 model_bs_to_find = [100, 200] ModelA.all( :joins=>{:model_a_to_b=>:model_bs}, :group=>"model_as.id", :select=>"model_as.*", :conditions=>["model_bs.id in (?)", model_bs_to_find], :having=>"count(*)=#{model_bs_to_find.size}") 

注意,以这种方式指定的组和选择参数将在MySQL中起作用,标准的SQL方法是将整个list_as列列表放在group和select参数中。