如何用Active Record查询完全不含指定食材的食谱?
查询完全不含指定食材的食谱(Active Record 实现)
直接给两种靠谱的实现方式,解决你遇到的问题:
方法1:左连接+分组统计
通过左连接保留所有食谱,再筛选出完全不包含目标食材的记录:
# 定义要排除的食材列表 excluded_ingredients = ['Cheese', 'Beef'] Recipe.left_joins(:ingredients) .where(ingredients: { name: excluded_ingredients }) .group('recipes.id') .having('COUNT(ingredients.id) = 0')
逻辑说明:左连接会保留所有食谱(哪怕没有任何食材),然后我们筛选出关联食材是要排除的那些记录,最后分组统计关联食材的数量——数量为0就说明这个食谱完全没用到指定食材。
方法2:NOT EXISTS子查询
逻辑更直观,先找出所有包含指定食材的食谱ID,再排除这些ID:
excluded_ingredients = ['Cheese', 'Beef'] Recipe.where.not( id: Ingredient.where(name: excluded_ingredients).select(:recipe_id) )
逻辑说明:子查询先拿到所有用到Cheese或Beef的食谱ID,外层查询直接排除这些ID,剩下的就是完全不含目标食材的食谱。
为啥你原来的写法会返回所有食谱?
大概率是用了内连接(joins(:ingredients))加where.not的组合——这种写法只会排除那些包含指定食材的关联行,但只要食谱有其他食材,还是会被返回;甚至连完全没有食材的食谱都会因为内连接被过滤掉,最后结果自然不对。
内容的提问来源于stack exchange,提问作者PrimeTimeTran
相关产品推荐
相关产品推荐

