2012-02-10 67 views
1

我試圖創建一個搜索,其中一個記錄必須在另一個表中有多個記錄(通過id和has_many語句鏈接)才能成爲作爲結果包括在內。Ruby on Rails:搜索一個表必須在另一個表中存在多行

我有表usersskill_lists,skill_maps

用戶通過skill_maps表中的單個條目映射到個人技能。許多用戶可以共享單個技能,單個用戶可以通過skill_maps表中的多個條目擁有許多技能。

例如

User_id | Skill_list_id 
2  | 9 
2  | 15 
3  | 9 

用戶2有技能9和15
用戶3有9

我試圖創建一個返回其具有一套技能的所有用戶的哈希搜索唯一的技能。所需的一組skill_ids在參數中顯示爲一個數組。

下面是我使用的代碼:

skill_selection_user_ids = SkillMap.find_all_by_skill_list_id(params[:skill_ids]).map(&:user_id) 

@results = User.find(:all, :conditions => {:id => skill_selection_user_ids}) 

的問題是,它返回有這些技能不是具有其全部用戶的所有用戶。

而且,我的用戶錶鏈接到skill_lists表:through => :skill_maps,反之亦然,這樣我可以調用@user.skill_list等等

我敢肯定,這是一個真正的新手問題,我完全新軌道(和編程)。我搜索並尋找解決方案,但找不到任何東西。我真的不知道如何在單個搜索詞中解釋這個問題。

回答

1

我個人不知道如何使用ActiveRecord的查詢界面來做到這一點。最容易做的事情是檢索誰都有每個人的技能的用戶列表,然後把這些列表的交集,也許使用設置:

require 'set' 

skills = [5, 10, 19] # for example 
user_ids = skills.map { |s| Set.new(SkillMap.find_all_by_skill_list_id(s).map(&:user_id)) }.reduce(:&) 
users = User.where(:id => user_ids.to_a) 

對於(可能)更高的性能,你可以「滾你擁有「SQL並讓數據庫引擎完成這項工作。如果您需要高性能,我可能會爲您提供一些SQL。 (或者如果有其他人可以,請編輯這個答案!)

順便說一句,你應該把skill_maps.skill_list_id作爲索引,以確保良好的性能,即使skill_maps表變得非常大。見ActiveMigration文檔:http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

+0

它的工作原理!非常感謝! 我必須先添加一個.to_a,然後才能通過這個新列表搜索我的用戶表。這裏是我的最終代碼: 'skill_selection_user_ids = params [:teach_skill_ids] .map {| s | Set.new(SkillMap.find_all_by_skill_list_id(s).map(&:user_id))} .reduce(:&) @results = User.find(:all,:conditions => {:id => skill_selection_user_ids.to_a} )' 再次感謝! – joshblour 2012-02-10 22:11:26

+0

你可以這樣做:'@results = User.find skill_selection_user_ids.entries'。 '條目'將集合轉換爲一個數組,您只需將其提供給'查找'。 – dynex 2012-02-11 00:27:22

+0

也工作過,謝謝@dynex! – joshblour 2012-02-11 21:36:57

1

你可能不得不使用一些自定義的SQL來獲取用戶ID。我在類似的HABTM關係上測試了這個查詢,它似乎工作:

SELECT DISTINCT(user_id) FROM skill_maps AS t1 WHERE (SELECT COUNT(skill_list_id) FROM skill_maps AS t2 WHERE t2.user_id = t1.user_id AND t2.skill_list_id IN (1,2,3)) = 3 

訣竅是在子查詢中。對於外部查詢的每一行,它找到的記錄該行匹配,你感興趣的任何技能,這一個計數。然後檢查是否那算技能總數匹配你有興趣。如果有匹配,那麼用戶必須擁有你搜索的所有技能。

你可以在Rails中使用find_by_sql執行此:

sql = 'SELECT DISTINCT(user_id) FROM skill_maps AS t1 WHERE (SELECT COUNT(skill_list_id) FROM skill_maps AS t2 WHERE t2.user_id = t1.user_id AND t2.skill_list_id IN (?)) = ?' 
skill_ids = params[:skill_ids] 
user_ids = SkillMap.find_by_sql([sql, skill_ids, skill_ids.size]) 

很抱歉,如果表和列的名稱不完全正確,但希望這是在球場。

相關問題