Laravel Eloquent多对多关联下如何用AND条件筛选联系人?
多对多关联下筛选同时拥有多个标签的联系人
表结构与模型定义
三张表呈多对多关联:
- Contact表
- Tag表
- ContactTag中间表,包含字段:
contact_id、tag_id
Contact模型的关联定义如下:
class Contact extends Model{ public function tags() { return $this->belongsToMany('App\Models\Tag', 'contact_tags', 'contact_id', 'tag_id'); } }
需求
需要获取同时拥有‘Sales Manager’和‘Product Manager’标签的联系人。
已尝试的错误写法及问题
- 使用
whereIn的写法,返回的是拥有任一标签的联系人(OR逻辑):
$tags = ['Sales Manager','Product Manager']; Contact::whereHas('tags', function($query) use ($tags){ $query->whereIn('name', $tags); })
whereIn本身是OR逻辑,只要联系人拥有任一指定标签就会被选中,不符合同时拥有的要求。
- 在同一个
whereHas闭包里叠加where,返回空数组:
Contact::whereHas('tags', function ($query) use ($tags) { $query->where('tags.name', $tags[0]); for ($i = 1; $i < count($tags); $i++) { $query->where('tags.name', $tags[$i]); } });
这种写法是要求单条Tag记录的name同时等于两个不同值,显然不存在这样的标签,因此返回空结果。
正确实现方法
方法一:多次调用whereHas
对每个标签分别使用whereHas,叠加筛选条件(AND逻辑):
$tags = ['Sales Manager', 'Product Manager']; $contacts = Contact::query(); foreach ($tags as $tagName) { $contacts->whereHas('tags', function ($query) use ($tagName) { $query->where('name', $tagName); }); } $contacts = $contacts->get();
每个whereHas都会过滤出拥有对应标签的联系人,多次叠加后,最终结果就是同时满足所有标签条件的联系人。
方法二:结合whereHas与计数筛选
先筛选出拥有任一目标标签的联系人,再通过指定关联记录数量等于目标标签总数,确保同时拥有所有标签:
$tags = ['Sales Manager', 'Product Manager']; $requiredTagCount = count($tags); $contacts = Contact::whereHas('tags', function ($query) use ($tags) { $query->whereIn('name', $tags); }, '=', $requiredTagCount)->get();
whereHas的第三个参数指定关联的匹配标签数量必须等于目标标签总数,以此保证联系人同时拥有所有指定标签。
内容的提问来源于stack exchange,提问作者Krishna Kanabar
相关产品推荐
相关产品推荐

