PHP
Filter Parent Models Based on Related Model Criteria with `whereHas`
Efficiently retrieve parent models only if their related models meet specific criteria, avoiding unnecessary data loading and improving query performance.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
public function products()
{
return $this->hasMany(Product::class);
}
}
class Product extends Model
{
use HasFactory;
public function category()
{
return $this->belongsTo(Category::class);
}
}
// Usage:
// Retrieve categories that have at least one product with 'available' status and price > 100
// $categoriesWithAvailableProducts = Category::whereHas('products', function ($query) {
// $query->where('status', 'available')
// ->where('price', '>', 100);
// })->get();
// Find users who have at least one published post
// $usersWithPublishedPosts = User::whereHas('posts', function ($query) {
// $query->where('status', 'published');
// })->get();
// You can also use 'orWhereHas' for OR conditions
// $categoriesWithCheapOrExpensiveProducts = Category::whereHas('products', function ($query) {
// $query->where('price', '<', 50);
// })->orWhereHas('products', function ($query) {
// $query->where('price', '>', 500);
// })->get();
How it works: The `whereHas` method allows you to filter results based on the existence of related models that satisfy specific conditions. Instead of loading all related models and then filtering, `whereHas` generates an efficient SQL `WHERE EXISTS` subquery, which significantly improves performance by only retrieving the parent models that meet the relationship criteria, making it ideal for filtering lists based on related data.