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

时间:2009-07-08 00:43:18

标签: sql ruby-on-rails database design-patterns

我有两个与HABTM相关的模型(实际上在两端使用has_many:through,以及一个连接表)。我需要检索与两个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.

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

上面比喻说,最后一个,你可以做一些事情,比如查询每个城市的所有人,然后找到每个阵列中存在的每个数组中的项目。这是至少5个查询,这些查询的所有数据都转移回应用程序,然后应用程序必须集中比较所有5个数组彼此(循环丰富!)。那太讨厌了吧?

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

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

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

你会如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

你可以这样做:

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

  2. 按条件在您需要的ModelA列上添加一个group(如果您愿意,甚至可以添加所有这些列)。 每行的计数()等于满足的ModelB条件数*。

  3. 添加'有'条件,仅选择count(*)等于您需要满足的ModelB条件数的行

  4. 示例:

    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}")
    

    N.B。以这种方式指定的group和select参数将在MySQL中运行,标准的SQL方法是将整个list_as列列表放在group和select参数中。

相关问题