雄辩的许多许多关系查询


Laravel 5 Eloquent ManyToMany relationship query

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

  • 鸡尾酒
  • cocktail_ingredient

我可以选择多个成分ID,例如[1,50,60,7,3]我需要找到只用这张配料表就能调制出的鸡尾酒。配料可以少一些,但它们都必须出现在我的配料表中[1,50,60,7,3]。

我声明了我的manymany关系,我创建了我的模型,一切正常,现在我尝试用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();

I tried also:

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

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

谢谢

在您的示例中,您的目标成分列表是[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]的鸡尾酒将返回,这不是您想要的。

你真正想要的是确保你只买到不含任何不在你的目标列表中的成分的鸡尾酒。[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();

这句话的意思是"把所有的鸡尾酒都拿过来,这些鸡尾酒的成分不在这个成分表中。"[1, 50]将匹配,因为它没有任何不在列表中的成分。然而,[1, 2]将不匹配,因为它确实有一个不在列表中的成分(2)。