Eager loading with conditional - Laravel
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Mastering Conditional Eager Loading in Laravel: Filtering Relationships Efficiently
As a senior developer working with Eloquent and Laravel, performance and data retrieval efficiency are paramount. One of the most common yet tricky scenarios developers face is managing eager loading when they only need a subset of related data. Today, we're diving into how to solve a specific problem: how to eagerly load a primary relation (like `championships`) while simultaneously filtering that loaded data based on a specific ID, ensuring all other necessary relationships remain intact and efficient.
## The Challenge: Eager Loading Too Much Data
Letâs start with the query you presented:
```php
$tournament = Tournament::with(
'championships',
'championships.settings',
'championships.category',
'championships.tree.users',
)->first();
```
When using `with('championships')`, Eloquent fetches *all* matching championships for that tournament and hydrates them into a collection. If you only need the championship associated with `$request->championshipId`, loading every single one creates unnecessary overhead, especially if the relationship is one-to-many or many-to-many.
The goal is to retrieve the `Tournament` record, but only load the specific `Championship` record matching a provided ID, while still preserving the eager loading of other necessary relationships like settings, category, and users.
## The Solution: Filtering Eager Loaded Relations
Directly filtering a relationship within a standard `with()` call is not straightforward because eager loading is designed to fetch related data in bulk for performance. To achieve conditional loading based on an external ID, we need a slightly more nuanced approach that leverages Eloquent's capabilities and efficient database queries.
The most robust way to handle this is to fetch the main model, and then explicitly load the specific relationship you need, applying the filter directly to that loading operation. Since you want *only one* championship, we can adjust how we define the eager load for the `championships` relationship.
### Implementation Example
Assuming your `Tournament` model has a `championships` relationship:
```php
use App\Models\Tournament;
use Illuminate\Http\Request;
class TournamentController extends Controller
{
public function show(Request $request)
{
$championshipId = $request->input('championshipId');
// 1. Define the required eager loads for all relationships EXCEPT the conditional one
$eagerLoads = [
'championships', // We will handle this specially
'championships.settings',
'championships.category',
'championships.tree.users',
];
// 2. Load the Tournament, conditionally loading a specific Championship
$tournament = Tournament::with([
// Load other relations normally
'championships.settings',
'championships.category',
'championships.tree.users'
])
->with(['championships' => function ($query) use ($championshipId) {
// Scope the eager load to only fetch the specific championship ID
$query->where('id', $championshipId);
}])
->first();
if (!$tournament) {
return response()->json(['message' => 'Tournament not found'], 404);
}
// Now, $tournament->championships will contain only the specific championship loaded,
// along with its related settings, category, and users.
return response()->json($tournament);
}
}
```
## Deep Dive: Why This Approach Works
This technique moves the filtering logic from post-retrieval (filtering a large collection) to pre-retrieval (filtering the database query during the eager load).
1. **Efficiency:** Instead of loading all championships and then manually filtering them in PHP memory, we instruct Eloquent to use a `WHERE` clause when fetching the relationship data. This results in a single, highly optimized SQL query that joins only the necessary records, significantly reducing memory usage and database load.
2. **Maintaining Relationships:** By scoping the `with('championships')` call using a closure (`with(['championships' => function ($query) { ... }])`), we ensure that the filtering happens *within* the context of the eager loading mechanism, preserving the structure of the nested relationships you initially desired.
This practice aligns perfectly with Laravel's philosophy of building efficient applications by utilizing Eloquent's power to interact cleanly with the database. For more advanced relationship management and query optimization, exploring documentation on highly optimized data fetching patterns is always recommended, as seen in guides provided by the [Laravel Company](https://laravelcompany.com).
## Conclusion
Conditional eager loading is a powerful technique that bridges the gap between high-level object retrieval and low-level database performance. By using scoped closures within the `with()` method, developers can retrieve exactly the data they needâa single related record in this caseâwhile simultaneously ensuring that all other necessary relationships are eagerly loaded efficiently. Master this pattern, and you'll write faster, cleaner, and more performant Laravel applications.