如何用Eloquent优雅实现关联表求和并按结果排序?
用Laravel Eloquent优雅实现按关联分数总和排序用户列表
首先得揪个小细节:你的Score模型类名写错成Job啦,先把这个修正过来,不然关联逻辑会出问题:
class Score extends Model { // 可以补充定义反向关联,让模型关系更完整 public function user() { return $this->belongsTo('App\User'); } }
回到你的核心需求:摆脱foreach循环,用更优雅的Eloquent写法实现用户列表按关联分数总和降序排列。原来的写法会触发N+1查询问题(先查所有用户,再循环每个用户单独查分数总和),而我们可以直接在数据库层面完成聚合计算和排序,既简洁又高效。
优化后的控制器代码
$users = User::withSum('scores', 'score') ->orderByDesc('scores_sum_score') ->get(); return view('homepage', [ 'users' => $users ]);
代码说明
withSum('scores', 'score'):Eloquent的这个方法会自动为每个用户计算关联scores表中score字段的总和,结果会存储在scores_sum_score属性中(命名规则是关联名_sum_字段名)orderByDesc('scores_sum_score'):直接在数据库层面按分数总和降序排序,比在PHP集合中排序性能提升明显- 最终每个
$user对象都会自带scores_sum_score属性,你可以在视图里直接用{{ $user->scores_sum_score }}展示总和
如果想给总和字段起个更贴合需求的名字(比如score_sum),可以用自定义字段名的写法:
use Illuminate\Support\Facades\DB; $users = User::withSum( ['scores' => fn($query) => $query->select(DB::raw('sum(score) as score_sum'))], 'score' ) ->orderByDesc('score_sum') ->get();
这样每个用户对象的属性就变成score_sum,和你预期结果里的字段名完全匹配。
这种方式只需要1次数据库查询,既避免了循环带来的冗余查询,代码也更符合Laravel Eloquent的优雅风格~
内容的提问来源于stack exchange,提问作者tonywei
相关产品推荐
相关产品推荐

