PHP
Optimizing Relationship Aggregates with Eloquent `withCount` and `withSum`
Learn to efficiently retrieve counts or sums of related models without loading all relationships, significantly improving query performance with `withCount` and `withSum`.
<?php
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
public function likes()
{
return $this->hasMany(Like::class);
}
}
// app/Models/Comment.php (Assuming comments have a 'score' column)
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['body', 'score'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
// Usage Example
// Retrieve posts and their comments count
$postsWithCounts = Post::withCount('comments')->get();
foreach ($postsWithCounts as $post) {
echo "Post: {$post->title}, Comments Count: {$post->comments_count}
";
}
// Retrieve posts, comments count, and total score of comments
$postsWithCountsAndSums = Post::withCount('comments')
->withSum('comments', 'score') // Sum the 'score' column of related comments
->get();
foreach ($postsWithCountsAndSums as $post) {
echo "Post: {$post->title}, Comments: {$post->comments_count}, Total Comment Score: {$post->comments_sum_score}
";
}
// You can also add conditional constraints
$postsWithSpecificCounts = Post::withCount(['comments' => function ($query) {
$query->where('is_approved', true);
}])->get();
foreach ($postsWithSpecificCounts as $post) {
echo "Post: {$post->title}, Approved Comments: {$post->comments_count}
";
}
How it works: The `withCount` and `withSum` methods provide an efficient way to retrieve the count or sum of related models without actually loading the entire relationship into memory. Instead of performing N+1 queries or complex joins, these methods add a `_count` or `_sum_column` attribute to the parent model directly within the initial query. This significantly optimizes performance when you only need an aggregate value from a relationship, and you can even apply conditional constraints to these aggregates.