Reader Stacks

How to Check If an Eloquent Collection Is Empty (and Count It Correctly)

count(), isEmpty(), isNotEmpty(), and the N+1-query mistake people make trying to "optimize" an empty check on an Eloquent relationship.

Eloquent collections extend Laravel's base Collection class, so the usual collection methods apply — but there are a couple of Eloquent-specific traps worth knowing.

Basic checks

$users = User::where('active', true)->get();

$users->count();       // int
$users->isEmpty();     // bool
$users->isNotEmpty();  // bool

count() on a query vs. count() on a collection

These look identical but do very different work:

User::where('active', true)->count();        // SQL: SELECT COUNT(*) ...
User::where('active', true)->get()->count();  // fetches every row, then counts in PHP

If you only need the number, the first form is almost always better — it never pulls the actual rows into memory. Only use ->get()->count() when you're already loading the collection for another reason and counting it is free.

Checking if a relationship is empty without an N+1 problem

A common but costly pattern:

foreach ($posts as $post) {
    if ($post->comments->isEmpty()) { // lazy-loads comments per post
        // ...
    }
}

Each $post->comments access triggers its own query unless the relationship was eager-loaded. Fix it with eager loading, or better, with a query-level existence check that never loads the related rows at all:

$posts = Post::withCount('comments')->get();

foreach ($posts as $post) {
    if ($post->comments_count === 0) {
        // ...
    }
}

withCount() runs a single additional aggregate query for the whole collection, rather than one query per row — the fix for the N+1 pattern above, not just a stylistic preference.

whereHas() vs a PHP-side filter

If the goal is filtering posts that have zero comments (not just checking, but excluding), do it in the query, not after fetching:

$posts = Post::whereDoesntHave('comments')->get();

This is a single SQL query with a NOT EXISTS subquery — far cheaper than fetching every post and filtering in PHP once the table has any real size.

Topics: Database Queries & Eloquent