2014-02-18 19 views
1

我有3個型號如下: (我也描述任何不熟悉的RubyOnRails的情況下,數據庫結構能夠幫助我)優化的方式通過的has_many檢索標識:通過關聯


Thread.rb

class Thread 
    has_many :thread_profils 
    has_many :profils, :through => :thread_profils 
end 

線程

integer: id (PK) 

ThreadProfil.rb

class ThreadProfil 
    belongs_to :thread 
    belongs_to :profil 
end 

thread_profils

integer: id (PK) 
integer: thread_id (FK) 
integer: profil_id (FK) 

Profil.rb

class Profil 
end 

異型材

integer: id (PK) 

在我的控制器之一,我尋找最優化的方式來找到具有線程標識包括正好 2個異型材(中當前之一,另一個):

我得到了我的current_profil.id和一個nother profil.id我找不到一個簡單的方法來獲得收集/列表/數組Thread.id,同時處理更少的SQL請求。


現在我發現的唯一解決方案是下面的一個,我根本不認爲它是「優化的」。

thread_profils = ThreadProfil.where(:profil_id => current_profil.id) 
thread_ids = thread_profils.map do | association | 
    profils = Thread.find(association.thread_id).profils.map do | profil | 
     profil.id if profil.id != current_profil.id 
    end.compact 
    if (profils - [id]).empty? 
    association.thread_id 
    end 
end.compact 

爲處理下面的SQL查詢:

SELECT `thread_profils`.* FROM `thread_profils` WHERE `thread_profils`.`profil_id` = [current_profil.id] 

併爲每個結果:

SELECT `threads`.* FROM `threads` WHERE `threads`.`id` = [thread_id] LIMIT 1 

SELECT `profils`.* FROM `profils` INNER JOIN `thread_profils` ON `profils`.`id` = `thread_profils`.`profil_id` WHERE `thread_profils`.`thread_id` = [thread_id] 

有任何光線的方式來做到這一點,無論是與導軌或直接與SQL?

感謝

回答

1

我發現下面的查詢在SQL:

SELECT array_agg(thread_id) FROM "thread_profils" WHERE "thread_profils"."profil_id" = 1 GROUP BY profil_id HAVING count(thread_id) =2 

注:array_agg是Postgres聚合函數。Mysql有group_concat,它會給你一個以逗號分隔的ID字符串而不是數組。

通過下面的Rails代碼生成這個SQL:

ThreadProfil.select('array_agg(mythread_id)').where(profil_id: 1).group(:profil_id).having("count(thread_id) =2").take 

這會產生正確的查詢,但結果是沒有意義的ThreadProfil - 不過,你也許可以用這進一步合作,以獲取你想要什麼。