2012-02-10 72 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]) 

很抱歉,如果表和列的名称不完全正确,但希望这是在球场。

相关问题