Eloquent: как отсортировать по сумме столбцов в другой таблице - PullRequest
3 голосов
/ 26 октября 2019

У меня есть 2 таблицы: пользователи и комментарии.

Каждый комментарий имеет оценку. Один пользователь может иметь много комментариев.

Это моя миграция

Schema::create('users', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('email', 120)->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    ......
});

Schema::create('comments', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->bigInteger('user_id')->unsigned();
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->string('commentable_type');
    $table->bigInteger('commentable_id');
    $table->char('enable', 1)->default(0);
    $table->char('to_stats', 1)->default(0);
    $table->tinyInteger('rating')->default(0);
    ...
});

Comment.php

class Comment extends Model
{
    ...
    public function commentable()
    {
        return $this->morphTo();
    }

    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

User.php

class User extends Authenticatable implements MustVerifyEmail
{
    ...
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }

    public function commentsReceived()
    {
        return $this->hasMany('App\Comment', 'commentable_id', 'id');
    }

    public function scopeOfRoleType($query, $types)
    {
        return $query->whereHas('roles', function ($q) use ($types) {
            $q->whereIn('name', $types);
        });
    }

    public function userRatingCount()
    {
        return $this->hasMany('App\Comment', 'commentable_id', 'id')->where('enable', '=', '1')->where('to_stats', '=', '0');
    }
}

Я хочу показать список пользователей, упорядоченный по итоговому столбцу рейтинга в таблице комментариев (скажем так, голоса). Затем мне нужно отобразить его от большинства голосов до самых маленьких.

Я пробую этот код, но он не работает:

$users = User::ofRoleType($role)->with('userRatingCount')->sum('comments.rating');

Как это исправить?

Ответы [ 2 ]

2 голосов
/ 26 октября 2019

Для этого можно использовать подзапрос.

Сначала нам нужно выяснить, как будет выглядеть запрос.

select `users`.*,
       (
           select sum(rating)
           from `comments`
           where `user_id` = `users`.`id`
       ) as `comments_rating`
from `users`
order by `comments_rating` desc

Затем нам просто нужно преобразовать этот запрос вКрасноречивый.

$commentsRating = Comment::selectRaw('sum(rating)')
    ->whereColumn('user_id', 'users.id')
    ->getQuery();

$users = User::select('users.*')
    ->selectSub($commentsRating, 'comments_rating')
    ->orderBy('comments_rating', 'DESC')
    ->get();

И последнее, но не менее важное, я покажу вам классную вещь. Мы можем переместить этот запрос в области. Таким образом, мы можем загрузить этот запрос, когда захотим.

class User extends Model
{
    public function scopeWithCommentsRating($query)
    {
        $commentsRating = Comment::selectRaw('sum(rating)')
            ->whereColumn('user_id', 'users.id')
            ->getQuery();

        $base = $query->getQuery();
        if (is_null($base->columns)) {
            $query->select([$base->from.'.*']);
        }

        return $query->selectSub($commentsRating, 'comments_rating');
    }
}

Затем,

$users = User::withCommentsRating()->orderBy('comments_rating', 'DESC')->get();

PS . Я не знаю, какова цель userRatingCount отношения.

0 голосов
/ 26 октября 2019
User::ofRoleType($role)->with('comments')->sortBy(function ($user) {
    return $user->comments->sum('rating');
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...