$ lexprog.com

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

[January 15, 2026] Eloquent ORM

Eloquent Aggregates: Without Loading Models

Eloquent Aggregates: Without Loading Models

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

Eloquent Aggregates: Without Loading Models

Tip: sum() on Query Builder

$total = Order::where('status', 'paid')->sum('total');

Single query, no model loading.

Gotcha: sum() on Collection

$total = $orders->sum('total');

Loads all models into memory first, then sums in PHP. Much slower for large datasets.

Tip: Multiple Aggregates

$stats = Order::selectRaw('
    COUNT(*) as total_orders,
    SUM(total) as revenue,
    AVG(total) as avg_order
')->first();

Gotcha: count() vs count Property

$posts->count(); // Query: SELECT COUNT(*)
$posts->count;   // Collection property

Tip: max() and min()

$latestPrice = Product::where('category_id', 1)->max('price');
$oldest = User::min('created_at');

Gotcha: avg() Returns Float

$avg = Order::avg('total'); // Returns float, not a model

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

Aggregate methods like withCount() are convenient but they add correlated subqueries that can be expensive on large datasets. I've seen an API endpoint with 10 withCount() calls on different relationships, generating a query with 10 subqueries — each scanning thousands of rows. For dashboards and listing pages, I prefer a single aggregate query instead of multiple withCount() calls.

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

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