是否有任何 Eloquent 方法来获取关系 table 的总和并对其进行排序?

Is there any Eloquent way to get sum of relational table and sort by it?

示例:

table 用户

ID | Username | sex
1  | Tony     | m
2  | Andy     | m
3  | Lucy     | f

table 分数

ID | user_id | score
1  | 2       | 4
2  | 1       | 3
3  | 1       | 4
4  | 2       | 3
5  | 1       | 1
6  | 3       | 3
7  | 3       | 2
8  | 2       | 3

预期结果:

ID | Username | sex | score_sum (sum) (desc)
2  | Andy     | m   | 10
1  | Tony     | m   | 8
3  | Lucy     | f   | 5

我目前使用的代码:

用户模型:

class User extends Authenticatable
{
    ...
    public function scores()
    {
        return $this->hasMany('App\Score');
    }
    ...
}

评分模型

class Job extends Model
{
   //i put nothing here
}

控制器中的代码:

$users = User::all();

foreach ($users as $user){
    $user->score_sum = $user->scores()->sum('score');
}

$users = collect($users)->sortByDesc('score_sum'); 
return view('homepage', [
    'users' => $users->values()->all()
]);

希望我上面的例子有意义。我的代码确实有效,但我认为必须有一种 Eloquent 和优雅的方式来做到这一点,而不需要 foreach?

Eloquent 有两种选择。

选项 1

第一种方法是将 score_sum 添加为查询 users 模型时始终包含的属性。如果您在查询 users table 时大部分时间都使用 score_sum,那么这只是一个好主意。如果您只需要在非常特定的视图或特定的业务逻辑上使用 score_sum,那么我会使用下面的第二个选项。

为此,您需要将属性添加到 users 模型,您可以在此处查看文档:https://laravel.com/docs/5.6/eloquent-mutators#defining-an-accessor

这是您的用例示例:

/app/User.php

class User extends Model
{
    .
    .
    .
    public function getScoreSumAttribute($value)
    {
        return $this->scores()->sum('score');
    }
}

选项 2

如果您只想针对单个用例执行此操作,那么最简单的解决方案就是在您将要使用的最终 foreach 循环中使用 sum() 函数(很可能在风景)。

例如在视图中:

@foreach($users as $user)
    <div>Username: {{$user->username}}</div>
    <div>Sex: {{$user->sex}}</div>
    <div>Score Sum: {{$user->scores()->sum('price')}}</div>
@endforeach

此外,如果您不想在 foreach 循环中执行此操作,您可以在控制器中的 Eloquent 调用中使用原始查询获取“score_sum”。这是一个如何做到这一点的例子:

$users = User::select('score_sum',DB::raw(SUM(score) FROM 'scores'))->get();

我没有快速环境来测试它,您可能需要在 DB::raw 查询中使用 WHERE 子句

希望对您有所帮助!

这真是太棒了:

User::selectRaw('*, (SELECT SUM(score) FROM scores WHERE user_id = users.id) as score_sum')
    ->orderBy('score_sum', 'DESC')
    ->get();