$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[July 20, 2024] Eloquent ORM

Eloquent When Loading: Conditional Relations

Eloquent When Loading: Conditional Relations

────────────────────────────────────────────────────────

Eloquent When Loading: Conditional Relations

Tip: loadWhen() for Conditional Loading

$post->loadWhen($includeComments, 'comments');

Only loads the relation if the condition is true.

Gotcha: loadMissing() Prevents Re-loading

$post->loadMissing('comments');

Only loads if the relation hasn't been loaded yet.

Tip: loadCount() Without Loading

$post->loadCount('comments');
echo $post->comments_count;

Gets the count without loading the actual relation data.

Gotcha: load() vs with()

with() eager loads in the initial query. load() lazy loads after the fact (additional query).

Tip: Conditional Eager Loading

Post::with(['comments' => function ($query) use ($request) {
    if ($request->boolean('approved_only')) {
        $query->where('approved', true);
    }
}])->get();

Gotcha: when() on Query Builder

Post::when($request->filled('category'), function ($q) use ($request) {
    $q->where('category_id', $request->category);
});

Tip: Use cursor() for Memory-Neutral Iteration

When exporting 100K rows, get() loads everything into memory. cursor() uses yield and keeps memory flat regardless of row count. Perfect for artisan commands.

Tip: whereHas() vs load() — Two Different Things

whereHas() filters the parent query by relationship existence. load() eager-loads relationships AFTER the query. Mixing them up is a common source of logic bugs.

Gotcha: withCount() Adds a Subquery

withCount('comments') runs a correlated subquery on every row. On large tables, this can be slower than a separate query. Profile before relying on it.

Senior Insight

Conditional relationship loading with when() and load() is a pattern I use daily, but it requires discipline. The danger: loading relationships in a loop instead of before the loop. I've refactored code that loaded the same relationship 50 times inside a foreach — each load() call was a separate query. Always load relationships before iterating, or use loadCount() if you only need the count.

Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)

────────────────────────────────────────────────────────
<-- back to posts