If you have a hasMany relationship and want to get the parent record with a total sum of specific children column values and order by it, here's how to do it.
Imagine you have this DB structure.
players
- id
 - name
 
games
- id
 - player_id
 - score
 
And the relationship is this:
app/Models/Player.php:
public function games(): HasMany{    return $this->hasMany(Game::class);}
Then, if you want to get the players with their total scores from all games, you can do this:
$players = Player::withSum('games', 'score')->get();
Then the result will be something like this:
Illuminate\Database\Eloquent\Collection {#1937    all: [      App\Models\Player {#2044        id: 1,        name: "Player 1",        created_at: "2023-07-11 07:41:44",        updated_at: "2023-07-11 07:41:44",        games_sum_score: "17",      },      App\Models\Player {#1234        id: 2,        name: "Player 2",        created_at: "2023-07-11 07:41:44",        updated_at: "2023-07-11 07:41:44",        games_sum_score: "13",      },    ],  }
As you can see, the child record total column is returned as [table]sum[column]
Want to order by total score and get the top 5 players? No problem.
Player::withSum('games', 'score')    ->orderBy('games_sum_score', 'desc')    ->limit(5)    ->get();
Here's the SQL query that would be executed under the hood:
select  `players`.*,  (    select      sum(`games`.`score`)    from      `games`    where      `players`.`id` = `games`.`player_id`  ) as `games_sum_score`from  `players`order by  `games_sum_score` desclimit  5
As you can see, this calculation also increases the performance, compared to the alternative that you would launch a separate loop to calculate the sum.
The withSum() executes one SQL query and returns only the sum column without needing more SQL queries or columns from the games table.
Laravel also offers similar methods for aggregating data:
- withCount()
 - withMax()
 - withMin()
 - withAggregate()
 
You can read about them in the official documentation.
                                                    
                                                    
                                                    
No comments or questions yet...