Reputation: 35
I want to list all posts have at least one tag on each category i selected. In our laravel app we have a Post and Tag model.
In Post model we have:
public function tags()
{
return $this->belongsToMany(Tag::class, 'post_tags', 'post_id', 'tag_id');
}
What is query to select post have atleast one of {3,2} tags and atleast one of {8,10} ?
I write this code:
$tags = ['news' => [3,2], 'alert' => [8,10]];
Post::whereHas('tags', function($query) use ($tags){
foreach($tags as $category => $tag){
$query->whereIn('tags.id', $tag);
}
}
posts
+---------+---------------+
| id | title |
+---------+---------------+
| 1 | post 1... |
| 2 | post 2... |
| 3 | post 3... |
| 4 | post 4... |
| 5 | post 5... |
| 6 | post 6... |
| 7 | post 7... |
| 8 | post 8... |
| 9 | post 9... |
+---------+---------------+
tags
+---------+-------+------------+
| id | name | category |
+---------+-------+------------+
| 1 | stock | news |
| 2 | acc | news |
| 3 | etc | news |
| 4 | eco | news |
| 5 | side | ads |
| 6 | head | ads |
| 7 | footer| ads |
| 8 | info | alert |
| 9 | danger| alert |
| 10 |success| alert |
+---------+-------+------------+
post_tags
+-----------+---------+
| post_is | tag_id |
+-----------+---------+
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
| 1 | 8 |
| 1 | 9 |
| 1 | 10 |
| 9 | 9 |
| 9 | 6 |
| 3 | 7 |
| 7 | 1 |
| 7 | 2 |
| 7 | 8 |
+-----------+---------+
But result is nothing.
I need result as Post Eloquent and query performance is important.
larave version is 5.8.35
Upvotes: 0
Views: 559
Reputation: 521289
I would start here with a raw MySQL query which gets the job done. Then, build your Laravel script around that.
SELECT
p.id,
p.title
FROM posts p
INNER JOIN post_tags pt
ON pt.post_id = p.id
GROUP BY
p.id,
p.title
HAVING
SUM(pt.tag_id IN (2, 3)) > 0 AND
SUM(pt.tag_id IN (8, 10)) > 0;
Your Laravel code:
$posts = DB::table('posts p')
->join('post_tags pt', 'pt.post_id', '=', 'p.id')
->groupBy('p.id', 'p.name')
->havingRaw('SUM(pt.tag_id IN (2, 3)) > 0 AND SUM(pt.tag_id IN (8, 10)) > 0')
->select('p.id', 'p.name')
->get();
Upvotes: 2