Filter Laravel Eloquent Query with relationship based on having multiple many-to-many-relationships

Updated: Feb 18, 2025

Filter Laravel Eloquent Query with relationship based on having multiple many-to-many-relationships

I. Introduction

In Laravel, Eloquent ORM provides a powerful and flexible way to work with databases. One of the most common use cases is filtering data based on certain conditions. However, when dealing with complex relationships, such as many-to-many relationships, filtering data can become more challenging. In this answer, we will explore how to filter a Laravel Eloquent query with multiple many-to-many relationships.

II. Prerequisites

Before we dive into the solution, let's first define the relationships we will be working with. Let's assume we have three models: User, Post, and Tag. A User has many Posts, and a Post belongs to a User. A Post can have multiple Tags, and a Tag can be associated with multiple Posts. This relationship setup is known as a many-to-many relationship, and it can be defined in Laravel using the belongsToMany and hasManyThrough methods.

// User model
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// Post model
class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }

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

// Tag model
class Tag extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(Post::class, User::class);
    }
}

III. Filtering data with multiple many-to-many relationships

To filter data with multiple many-to-many relationships, we can use the whereHas method in combination with the with method. The whereHas method allows us to filter records based on a relationship existence, while the with method eager loads the relationships.

Let's say we want to retrieve all the User records that have Posts with the tag: 'example'. We can achieve this by using the following query:

$users = User::with(['posts.tags' => function ($query) {
    $query->where('name', '=', 'example');
}])->has('posts.tags')->get();

In this query, we are eager loading the posts relationship on the User model and the tags relationship on the Post model using the hasManyThrough relationship defined in the Tag model. We are then using the whereHas method to filter the tags relationship based on the condition name = 'example'.

IV. Conclusion

Filtering data with multiple many-to-many relationships in Laravel Eloquent can be achieved using the whereHas method in combination with the with method. This approach allows us to filter records based on the existence of a relationship and eager load the relationships to improve performance. By understanding the relationships and using the appropriate methods, we can effectively filter complex data in Laravel.