$ lexprog.com

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

[July 14, 2026] Eloquent ORM

Eloquent Relationship Existence: Checks

Eloquent Relationship Existence: Checks

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

Eloquent Relationship Existence: Checks

Tip: exists() on Relation

if ($post->comments()->exists()) {
    // Has comments
}

Single EXISTS query.

Gotcha: count() vs exists()

$post->comments()->count() > 0; // Loads count
$post->comments()->exists();    // Faster - just checks existence

Tip: doesntExist()

if ($post->comments()->doesntExist()) {
    // No comments
}

Gotcha: Loaded Relation Check

if ($post->comments->isNotEmpty()) {
    // Checks loaded collection
}

Only works if relation is already loaded.

Tip: whereHas with Count

Post::whereHas('comments', fn($q) => $q, '>=', 5)->get();

Posts with 5+ comments.

Gotcha: has() Shorthand

Post::has('comments')->get();

Posts with at least one comment.

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: Pivot Data Is Read-Only by Default

Many-to-many pivot columns are read-only unless you define custom pivot models. Use ->withPivot('expires_at') to make them accessible, and newPivot() to make them writable.

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

Checking relationship existence with has() is convenient, but the generated SQL varies significantly between database engines. On PostgreSQL, has() generates an EXISTS clause. On SQLite, it generates a subquery. For critical queries, I check the generated SQL with toSql() on both databases if we support both. The performance characteristics can be dramatically different.

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

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