Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dgvai's avatar
Level 1

Get data by belongsToMany relation in 'where' query

I am literally confused about how to proceed with the query.

I have two models:

  • Product
  • Tag

Product - Tag are related by many-to-many relationship.

So:

// Product.php

    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }

// in Tag.php 

    public function products()
    {
        return $this->belongsToMany(Product::class);
    }

Lets, query products by some tags (id), say lets find the products who has 1,2 and 3 (id) Tags.

The query should result like:

  • Product1: Tags [1,2,3,5]
  • Product2: Tags [1,2,3]
  • Product3: Tags [1,2,3,4,5,6]

Basically what I meant:

$tags = $request->tags;   // [1,2,3]
Product::where(...)->get()  // where tags includes [1,2.3]
0 likes
15 replies
automica's avatar

@dgvai try this:

gets all products that have tag ids from request

    $matchTags = $request->tags;

    $products = Product::whereHas('tags', function($query) use ($matchTags) {

        $query->whereIn('tags.id', $matchTags);

    })->get();
MichalOravec's avatar
$products = Product::whereHas('tags', function ($query) use ($request) {
    $query->distinct()->whereIn('id', $request->tags);
}, '=', count($request->tags))->get();
automica's avatar

@michaloravec can you explain what the extra bit

, '=', count($request->tags)

is doing? Are you ensuring the numbers of tags that the product has is the number of tags being passed into the request?

MichalOravec's avatar

He needs to find products which have all those tags. And not just one of them.

Something like whereIn all.

2 likes
shami003's avatar

@michaloravec what if I want to get products if there is no tags selected, so I can gat all products if $request->tags == null

MichalOravec's avatar

@shami003 In that case use conditional clause with doesntHave

$products = Product::when($request->tags, function ($query, $tags) {
    return $query->whereHas('tags', function ($query) use ($tags) {
        $query->distinct()->whereIn('id', $tags);
    }, '=', count($tags));
}, function ($query) {
    return $query->doesntHave('tags');
})->get();

https://laravel.com/docs/8.x/queries#conditional-clauses

https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-absence

2 likes
shami003's avatar

@michaloravec I have to put other where before when ?

For each $request if it is null I am returning all users

$students = Student::where('room_id', $request->input('room'))
                                ->where('status', $request->input('status'))
                                ->whereHas('tags', function ($query) use ($tags) {
                                    $query->distinct()->whereIn('id', $tags);
                                })->get();

In this case $request->tags is always null because it is coming from a form

shami003's avatar

I have used below code as my solution, @michaloravec thanks for the idea

$students = Student::when($request->input('room') != null , function ($query) use ($request) {
                return $query->where('room_id', $request->input('room'));
            }, function ($query) {
                return $query;
            })->when($request->input('status') != null , function ($query) use ($request) {
                return $query->where('status', $request->input('status'));
            }, function ($query) {
                return $query;
            })->when($request->input('tags') != null , function ($query) use ($request) {
                return $query->whereHas('tags', function ($query) use ($request) {
                    $query->distinct()->whereIn('id', $request->input('tags'));
                });
            }, function ($query) {
                return $query;
            })->get();

Please or to participate in this conversation.