Laravel Eloquent
Using Eloquents withCount() and orderBy() with relation
Eloquent has function called withCount(): it helps to get the amount of related records inside of the main object. https://laravel.com/docs/eloquent-relationships#counting-related-models
Sometimes using withCount and orderBy may be slow and using Query Builder might be better approach. Example:
User::query()
->withCount([
'ratings' => function ($query) use ($from, $to) {
return $query->whereBetween('date', [$from, $to]);
}
])
->orderByDesc('ratings_count')
->limit(20);
Translates to raw SQL:
select
"user".username,
(
select
count(id)
from
"rating"
where
"user"."id" = "rating"."user_id"
and "date" between '2020-09-01 00:00:00'
and '2020-09-30 23:59:59'
) as ratings_count
from
"user"
order by
ratings_count desc
limit
20;
-- takes ~370ms
Instead we can write this:
User::query()
->join('rating', 'user.id', 'rating.user_id')
->select('user.*', DB::raw('count(rating.id) as ratings_count'))
->whereBetween('rating.date', [$from, $to])
->groupBy('user.id')
->orderBy('ratings_count', 'desc');
select
"user" .username ,
count(rating.id) as ratings_count
from
"user"
inner join "rating" on
"user"."id" = "rating"."user_id"
where
"rating"."date" between '2020-09-01 00:00:00' and '2020-09-30 23:59:59'
group by
"user"."id"
order by
"ratings_count" desc
limit 20
-- takes ~50ms