简体   繁体   中英

Laravel get posts have atleast one tag on each category of tags

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

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();

I think you forgot to write get() method and also missing closing bracket.

Try with below query:

$posts = Post::whereHas('tags', function($query) use ($tags){
           foreach($tags as $category => $tag){
              $query->whereIn('tags.id', $tag);
           }
         })->get();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM