【Laravel】リレーション先のカラムの合計値を元にランキングを取得する & IDを元にランク数取得

例えばユーザー (users) がブログ (posts) を投稿できるポータルサイトがあるとする
その際にユーザーのブログの閲覧数でランキングを作る方法

ソート方法はこちらにも記載してるやつ

ランキング一覧

  • web/routes.php
// ...省略

// ランキング一覧
Route::get('/ranking', [RankingController::class, 'index'])->name('ranking.index');
  • App/Controllers/RankingController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;

class RankingController extends Controller
{
    public function index()
    {
        $users = User::query()
            ->withCount([
                'posts AS total_view_count' => function ($query) {
                    $query->select(DB::raw("SUM(view_count) as view_count_sum"));
                }
            ])->orderBy('total_view_count', 'desc')
            ->get();
       
        return view('ranking.index', compact('users'));
    }
}
  • resources/views/ranking/index.blade.php
@foreach ($users as $index => $user)
  <div>ランキング: {{ $index + 1 }}位</div>
  <div>{{ $user->name }}</div>
@endforeach
ソート部分に関して
$users = User::query()
            ->withCount([
                'posts AS total_view_count' => function ($query) {
                    $query->select(DB::raw("SUM(view_count) as view_count_sum"));
                }
            ])->orderBy('total_view_count', 'desc')
            ->get();

withCountでリレーション先のpostsのカウントを取得する
ただ何も指定しないと、postsの合計数になってしまうので、
function内のselect(DB::raw("SUM(view_count)...にて閲覧数の合計total_view_countとして取得するようにカスタマイズしてる

あとはorderByでそのtotal_view_countを指定してあげればOK

ユーザーIDを元にその人のランク数を取得する

詳細画面などでその人のランクを表示したい場合

  • App/Controllers/RankingController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;

class RankingController extends Controller
{
    public function show(User $user)
    {
        $users = User::query()
            ->withCount([
                'posts AS total_view_count' => function ($query) {
                    $query->select(DB::raw("SUM(view_count) as view_count_sum"));
                }
            ])->orderBy('total_view_count', 'desc')
            ->get();

        $rank = array_search($user_id, $users->pluck('id')->toArray()) + 1;
       
        return view('ranking.show', compact('user', 'rank'));
    }
}

$usersにはCollectionが入っているのでpluck('id')->toArray()でIDのみの配列にし、array_searchでindex検索してる

あとはview側で {{ $rank }}位のように表示すればOK

\ 案件のご依頼・ご相談はこちらから /