PHP

Efficiently Aggregate Related Data with `withCount`, `withSum`, and `withMax`

Optimize database queries by aggregating related model data like counts, sums, and averages directly within the parent query using Eloquent's `withCount`, `withSum`, and `withMax`.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = ['title'];

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

class Comment extends Model
{
    protected $fillable = ['post_id', 'content', 'likes'];

    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

// Setup some dummy data
$post1 = Post::create(['title' => 'My First Post']);
$post1->comments()->create(['content' => 'Great post!', 'likes' => 10]);
$post1->comments()->create(['content' => 'Loved it.', 'likes' => 5]);

$post2 = Post::create(['title' => 'Another Post']);
$post2->comments()->create(['content' => 'Interesting read.', 'likes' => 20]);

// Get posts with their comments count
$postsWithCounts = Post::withCount('comments')->get();
foreach ($postsWithCounts as $post) {
    echo "Post: {$post->title}, Comments Count: {$post->comments_count}
";
}

echo "
";

// Get posts with total likes on comments, aliasing the result column
$postsWithLikesSum = Post::withSum('comments as total_comment_likes', 'likes')->get();
foreach ($postsWithLikesSum as $post) {
    echo "Post: {$post->title}, Total Comment Likes: {$post->total_comment_likes}
";
}

echo "
";

// Get posts with the latest comment creation date
$postsWithLatestComment = Post::withMax('comments as latest_comment_at', 'created_at')->get();
foreach ($postsWithLatestComment as $post) {
    echo "Post: {$post->title}, Latest Comment At: {$post->latest_comment_at}
";
}

echo "
";

// Multiple aggregations in a single query
$postsWithAggregates = Post::withCount('comments')
                           ->withSum('comments as total_likes', 'likes')
                           ->withAvg('comments as average_likes', 'likes')
                           ->get();
foreach ($postsWithAggregates as $post) {
    echo "Post: {$post->title}, Comments: {$post->comments_count}, Total Likes: {$post->total_likes}, Avg Likes: {$post->average_likes}
";
}
How it works: This snippet demonstrates how to use Eloquent's aggregation methods like `withCount`, `withSum`, `withMax`, and `withAvg` to efficiently retrieve aggregated data from related models. Instead of loading all related models and then performing calculations in PHP (which can lead to N+1 query issues), these methods execute a subquery to calculate the aggregate value directly within the main query. The result is a new attribute (e.g., `comments_count`, `total_comment_likes`) appended to the parent model instance, providing an optimized way to display summary data.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs