2009-07-08 39 views
3

我有兩個與HABTM相關的模型(實際上在兩端都使用has_many:through以及一個連接表)。我需要檢索與兩個ModelB的BOTH相關的所有ModelA。我不希望ModelB_1的所有ModelAs與ModelB_2的所有ModelAs連接。我真的希望所有與ModelB_1和ModelB_2都相關的ModelA。它不僅限於2個ModelB,它最多可以有50個ModelB,因此這必須進行縮放。HABTM用「AND」找到並非「OR」

我可以描述使用各種類比的問題,我認爲更好地描述我的問題比前面的段落:

* 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進行查詢並找到所有ModelA。

你會如何解決這個問題?

+0

我特別喜歡在自定義查詢中以某種方式使用JOIN和GROUPING來幫助執行此操作的方法。 SQL創意受到歡迎! – 2009-07-08 00:48:05

回答

4

你可以這樣做:

  1. 從MODELA構建查詢,加盟ModelB(通過連接模型),過濾是有你正在尋找一個值的ModelBs,即把他們在OR(即where ModelB = 'ModelB_1' or ModelB = 'ModelB_2')。 使用此查詢,結果集將具有多個'ModelA'行,每個ModelB條件只有一行滿足

  2. 通過條件在您需要的ModelA列上添加一個組(如果您願意的話,甚至可以包含所有這些組)。 每行的計數()等於滿足的ModelB條件的數量*。

  3. 添加一個「具有」條件只選擇其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方法是將model_as列的整個列表放在組和參數中。

+0

令人驚歎!它效果很好。以這種方式將GROUP BY和HAVING添加到SQL查詢中工作得很完美。我將在短時間內測試上面說明的Ruby方式。 – 2009-07-08 19:36:18