Laravel 5 Eloquent 多对多关系查询
Laravel 5 Eloquent ManyToMany relationship query
在我的 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();
总是计数错误,我知道我的问题出在我的 whereHas Closure 上,但我找不到它。
谢谢
在您的示例中,您的目标成分列表是 [1,50,60,7,3]
。想象一下,您有一种需要成分 [1, 2]
.
的鸡尾酒
根据您目前的逻辑:
has('ingredients', '<=', count($ids))
将匹配,因为 2 <= 5
和
whereHas('ingredients', function($q) use ($ids) { $q->whereIn('ingredients.id', $ids); })
将匹配,因为子查询将 return id 1 的记录,并且默认情况下,whereHas
仅查找至少一条记录。
因此,根据该逻辑,含有 [1, 2]
成分的鸡尾酒将 returned,这不是您想要的。
您真正要寻找的是确保您只获得不含任何不在目标 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();
此语句表示 "get all the cocktails that don't have an ingredient that is not in this list of ingredients." [1, 50]
将匹配,因为它没有任何不在列表中的成分。但是,[1, 2]
不会匹配,因为它确实有一个不在列表中的成分 (2
)。
在我的 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();
总是计数错误,我知道我的问题出在我的 whereHas Closure 上,但我找不到它。
谢谢
在您的示例中,您的目标成分列表是 [1,50,60,7,3]
。想象一下,您有一种需要成分 [1, 2]
.
根据您目前的逻辑:
has('ingredients', '<=', count($ids))
将匹配,因为2 <= 5
和whereHas('ingredients', function($q) use ($ids) { $q->whereIn('ingredients.id', $ids); })
将匹配,因为子查询将 return id 1 的记录,并且默认情况下,whereHas
仅查找至少一条记录。
因此,根据该逻辑,含有 [1, 2]
成分的鸡尾酒将 returned,这不是您想要的。
您真正要寻找的是确保您只获得不含任何不在目标 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();
此语句表示 "get all the cocktails that don't have an ingredient that is not in this list of ingredients." [1, 50]
将匹配,因为它没有任何不在列表中的成分。但是,[1, 2]
不会匹配,因为它确实有一个不在列表中的成分 (2
)。