Laravel中如何基于共享标签为每个Place查询关联Books?
解决方案:为Place获取共享标签的Books
你的场景是两个独立的多对多关联(Books ↔ Tags、Places ↔ Tags),而非多态关联,所以不用纠结多态的方案,直接通过关联查询就能实现需求。下面分MySQL原生语句和Laravel Eloquent两种方式说明:
一、MySQL原生查询
方式1:子查询+IN语句
先获取目标Place关联的所有Tag ID,再筛选关联这些Tag的Books,最后去重(避免同一Book因多个共享Tag重复出现):
SELECT DISTINCT b.* FROM books b JOIN book_tags bt ON b.id = bt.book_id WHERE bt.tag_id IN ( SELECT pt.tag_id FROM place_tags pt WHERE pt.place_id = 1 -- 替换成你的目标Place ID );
方式2:多表JOIN(性能更优)
直接通过Tag ID关联三张表,同样去重:
SELECT DISTINCT b.* FROM books b JOIN book_tags bt ON b.id = bt.book_id JOIN place_tags pt ON bt.tag_id = pt.tag_id WHERE pt.place_id = 1; -- 替换成你的目标Place ID
二、Laravel Eloquent实现
假设你已经在模型中定义了多对多关联:
Book模型:public function tags() { return $this->belongsToMany(Tag::class); }Place模型:public function tags() { return $this->belongsToMany(Tag::class); }
方式1:基于已加载的Place Tags
先获取目标Place,再通过whereHas筛选关联共享Tag的Books:
$placeId = 1; // 目标Place ID $place = Place::find($placeId); $relatedBooks = Book::whereHas('tags', function ($query) use ($place) { $query->whereIn('tags.id', $place->tags->pluck('id')); })->distinct()->get();
方式2:子查询关联(更高效,避免提前加载Tags)
直接在查询中关联place_tags表,减少一次数据库查询:
use Illuminate\Support\Facades\DB; $placeId = 1; $relatedBooks = Book::whereHas('tags', function ($query) use ($placeId) { $query->whereExists(function ($subQuery) use ($placeId) { $subQuery->select(DB::raw(1)) ->from('place_tags') ->whereColumn('place_tags.tag_id', 'tags.id') ->where('place_tags.place_id', $placeId); }); })->distinct()->get();
两种方式都能帮你精准获取到和指定Place拥有共同标签的所有Books,根据你的实际场景选择即可~
内容的提问来源于stack exchange,提问作者Michał
相关产品推荐
相关产品推荐

