Laravel 5 Eloquent ManyToMany关系查询

时间:2016-10-30 04:32:49

标签: php laravel laravel-5 eloquent laravel-5.3

在我的mySQL数据库中,我有3个表:

  • 鸡尾酒
  • 成分
  • cocktail_ingredient

我可以选择多种成分ID,例如。 [1,50,60,7,3] 我需要找到我可以准备的鸡尾酒,只有这些成分列表。可能含有较少的成分,但它们必须存在于我的成分列表中[1,50,60,7,3]。

我宣布了我的ManyToMany关系,我创建了我的模型,一切正常,现在我尝试使用ORM创建我的查询:

    $ids = [1,50,60,7,3];
    $coktails = Cocktail::has('ingredients','<=',count($ids))
                        ->whereHas('ingredients',function($q) use ($ids){
                            $q->whereIn('ingredients.id',$ids);
                        })
                        ->get();

我也试过了:

    $coktails = Cocktail::has('ingredients','<=',count($ids))
                        ->whereHas('ingredients',function($q) use ($ids){
                            foreach ($ids as $id){
                                $q->where('ingredients.id',$id);
                            }
                        })
                        ->get();

总是一个错误的计数,我知道我的问题在于我的关闭,但我无法找到它。

谢谢

1 个答案:

答案 0 :(得分:2)

在您的示例中,您的目标成分列表为[1,50,60,7,3]。想象一下,你有一种鸡尾酒需要成分[1, 2]

根据您当前的逻辑:

  • has('ingredients', '<=', count($ids))将匹配,因为2 <= 5
  • whereHas('ingredients', function($q) use ($ids) { $q->whereIn('ingredients.id', $ids); })将匹配,因为子查询将返回id 1的记录,默认情况下,whereHas仅查找至少一条记录。

所以,根据这个逻辑,将返回成分[1, 2]的鸡尾酒,而这不是你想要的。

您真正想要的是确保您只能获得没有任何不在您的目标ID列表中的成分的鸡尾酒。 [1, 50]应该匹配,因为它是一个子集,但[1, 2]不应该匹配,因为成分2不在原始集合中。

要处理此问题,您需要使用whereDoesntHave方法和whereNotIn方法的组合。

$ids = [1,50,60,7,3];
$cocktails = Cocktail::whereDoesntHave('ingredients', function($q) use ($ids) {
                        $q->whereNotIn('ingredients.id', $ids);
                    })
                    ->get();

这句话说&#34;得到所有没有成分列表中没有的成分的鸡尾酒。&#34; [1, 50]会匹配,因为它没有任何不在列表中的成分。但是,[1, 2]将不匹配,因为它的成分不在列表中(2)。