如何编写Rails查询精准匹配用户指定技能及对应等级?
解决方法
情况1:用户必须拥有所有指定技能-等级对(允许有其他技能)
要精准匹配每个技能对应的等级,不能用原代码的独立条件,得确保用户的技能集合里包含每一组指定的技能名+等级组合,下面两种方式都能实现:
方式1:多条件 EXISTS 子查询
针对每个技能-等级对,单独检查用户是否存在对应的Skill记录,逻辑最清晰:
def user_exists?(skill_level_pairs) # 参数格式示例: [{name: 'skill_1', level: 'level_a'}, {name: 'skill_2', level: 'level_b'}, {name: 'skill_3', level: 'level_c'}] query = User.all skill_level_pairs.each do |pair| query = query.where( User.exists( skills: { user_id: User.arel_table[:id], skill_name: pair[:name], skill_level: pair[:level] } ) ) end query.exists? end
方式2:分组统计匹配数量
通过关联Skill表过滤出匹配的记录,按用户分组后,确保匹配的不同技能数等于指定的技能对总数:
def user_exists?(skill_level_pairs) # 把技能-等级对拼接成SQL条件 conditions = skill_level_pairs.map { |p| "(skill_name = '#{p[:name]}' AND skill_level = '#{p[:level]}')" }.join(' OR ') User.joins(:skills) .where(conditions) .group('users.id') .having("COUNT(DISTINCT skills.skill_name) = ?", skill_level_pairs.size) .exists? end
如果用户可能有同技能同等级的多条记录,把COUNT(DISTINCT skills.skill_name)换成COUNT(DISTINCT skills.id)更稳妥。
情况2:用户恰好只拥有指定的技能-等级对(无其他技能)
如果“恰好”是指用户只有这三个技能且等级完全对应,除了满足上述匹配条件,还要验证用户的技能总数等于指定数量:
def user_exists_exact?(skill_level_pairs) required_count = skill_level_pairs.size User.joins(:skills) .group('users.id') # 确保每个指定的技能-等级对都存在 .having( skill_level_pairs.map { |p| "SUM(CASE WHEN skill_name = '#{p[:name]}' AND skill_level = '#{p[:level]}' THEN 1 ELSE 0 END) >= 1" }.join(' AND ') ) # 确保没有额外的技能 .having("COUNT(skills.id) = ?", required_count) .exists? end
原代码的问题
原代码User.joins(:skills).where(skill_name: skills, skill_level: levels)的逻辑是:匹配技能名在列表里且等级在列表里的记录,这会把只匹配了部分技能、或者技能和等级不对应的用户也查出来,完全不符合“恰好匹配指定技能及对应等级”的要求。
内容的提问来源于stack exchange,提问作者user137717
相关产品推荐
相关产品推荐

