Laravel Where Count > N
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Laravel Where Count > N: Mastering Relationship Filtering with Eloquent
As developers working with relational data in Laravel, managing complex filtering based on the *number* of related records is a common requirement. When you have a many-to-many relationship, like between `Customer` and `Car`, finding customers who possess fewer than $N$ cars requires careful use of Eloquent's querying capabilities.
Let’s dive into the scenario you presented: finding all customers who have less than 2 cars, where the threshold (2) is dynamic. We will analyze why your initial attempt might have failed and explore the most robust, performant solutions available in the Laravel ecosystem.
## The Challenge: Filtering Based on Related Record Counts
You have two models, `Customer` and `Car`, linked by a pivot table. You need to query for customers where the count of associated cars is less than a variable number ($N$).
Your initial attempt using `whereHas` with a raw subquery is a valid approach, but it can sometimes be overly complex or inefficient when dealing with simple aggregations.
```php
// Your original attempt (which didn't work as expected)
$customers = Customer::whereHas("cars", function($query) {
$query->selectRaw("count(*) < ?", [2]);
})->get();
```
While this structure attempts to filter the related relationship, often when mixing `whereHas` with complex aggregate functions within it, Eloquent’s query builder can struggle to translate it into the most optimized SQL.
## Solution 1: The Idiomatic Eloquent Approach using `withCount`
For filtering based on counts, the most idiomatic and often clearest way in Laravel is to utilize the `withCount` method first. This pre-calculates the count for every related model, making subsequent filtering straightforward using a standard `where` clause.
This approach separates the counting logic from the main filtering logic, leading to cleaner code and better readability. It aligns perfectly with the principle of keeping Eloquent relationships simple while leveraging the database's power.
Here is how you implement finding customers with less than $N$ cars:
```php
$threshold = 2;
$customers = Customer::withCount('cars')
->where('cars_count', '<', $threshold)
->get();
```
### Explanation of the `withCount` Method
1. **`withCount('cars')`**: This instructs Eloquent to perform a LEFT JOIN and aggregate the results, creating a new column (named `cars_count` by default) on the `customers` table that holds the total number of related records from the `cars` table for each customer.
2. **`where('cars_count', '<', $threshold)`**: We then apply a standard Eloquent `where` clause directly against this newly created, aggregated column. This is highly performant because the database handles the counting aggregation before the filtering step.
This method is excellent practice for any complex data retrieval in Laravel, promoting clean separation of concerns—a core tenet reflected in how high-quality frameworks like Laravel are designed to operate.
## Solution 2: The Pure SQL Approach (For Maximum Performance)
If performance on extremely large datasets becomes a critical concern, or if you need more complex aggregations that Eloquent struggles to map cleanly, falling back to explicit database joins and grouping can offer superior speed. This approach directly leverages raw SQL power.
```php
$threshold = 2;
$customers = DB::table('customers')
->join('customer_cars', 'customers.id', '=', 'customer_cars.customer_id')
->select('customers.*')
->groupBy('customers.id')
->having(DB::raw('COUNT(customer_cars.car_id)'), '<', $threshold)
->get();
```
While this requires writing raw SQL, it is the most direct translation of the relational algebra you need. For simple