如何在pivot table中筛选含指定全部食材ID的食谱?
多食材匹配食谱搜索问题解决
需求说明
开发一个搜索页面,支持输入多个食材ID,仅输出包含所有输入食材的食谱。食材与食谱的关联数据存储于pivot表ingredient_recipe中,表结构如下:
| id | ingredient_id | recipe_id | |----|---------------|-----------| | 1 | 1 | 1 | | 2 | 2 | 1 | | 3 | 1 | 2 | | 4 | 2 | 3 |
示例:当搜索食材ID为1和2时,仅应输出食谱ID为1的结果(食谱2、3仅含其中一种食材)。
问题代码及报错
用户尝试的代码:
$recipes_with_ingredient1 = DB::table('ingredient_recipe') ->where('ingredient_id', $ingredient_id)->pluck('recipe_id'); $recipes_with_ingredient2 = DB::table('ingredient_recipe')->where('ingredient_id', 2)->pluck('recipe_id'); $result=array_intersect($recipes_with_ingredient1,$recipes_with_ingredient1);
报错信息(翻译后):
array_intersect(): 参数 #1 ($array) 必须是 array 类型
问题分析
- Laravel的
pluck()返回的是Collection对象,不是原生PHP数组,直接传入array_intersect会触发类型错误。 - 代码里
array_intersect的第二个参数写错了,重复使用了$recipes_with_ingredient1,应该是$recipes_with_ingredient2。 - 这种逐个查询再取交集的方式扩展性差,食材数量多的时候代码会非常冗余。
解决方案
方案一:修正现有代码(适合少量食材)
把Collection转为数组,同时修正参数错误:
// 将查询结果转为原生数组 $recipes_with_ingredient1 = DB::table('ingredient_recipe') ->where('ingredient_id', $ingredient_id) ->pluck('recipe_id') ->toArray(); $recipes_with_ingredient2 = DB::table('ingredient_recipe') ->where('ingredient_id', 2) ->pluck('recipe_id') ->toArray(); // 修正第二个参数,取两个数组的交集 $result = array_intersect($recipes_with_ingredient1, $recipes_with_ingredient2);
方案二:更优的SQL聚合查询(支持任意数量食材)
直接通过SQL分组筛选,效率更高且扩展性强,不管输入多少食材都能用:
// 假设用户输入的食材ID数组是$ingredient_ids $ingredient_ids = [1, 2]; $required_ingredient_count = count($ingredient_ids); $result = DB::table('ingredient_recipe') ->whereIn('ingredient_id', $ingredient_ids) ->groupBy('recipe_id') ->havingRaw('COUNT(DISTINCT ingredient_id) = ?', [$required_ingredient_count]) ->pluck('recipe_id') ->toArray();
逻辑说明:
whereIn先筛选出包含任意指定食材的关联记录groupBy('recipe_id')按食谱ID分组havingRaw统计每组中不同食材的数量,只有数量等于输入食材总数的分组(也就是包含所有指定食材的食谱)才会被保留
内容的提问来源于stack exchange,提问作者Niek Neuvel
相关产品推荐
相关产品推荐

