Как лучше всего провести строку в таблице в Laravel? - PullRequest
3 голосов
/ 06 августа 2020

У меня в базе есть следующие таблицы: Database relationship

I would like to list videos with the best rating of comments, like this:
List database content

app/Helpers/function.php

function best_comment($data, $value = 'name') {
    $properties = array();

    foreach($data->episodes as $episode) {
        if(! isset($properties['id']) || $properties['id'] > $season->bestComment[0]->id) {
            $properties['id'] = $season->bestComment[0]->id;
            $properties['name'] = $season->bestComment[0]->name;
        }
    }
    
    if(! empty($properties)) {
        return $properties[$value];
    }
}

app/Video.php

public function episodes() {
    return $this->hasMany(Episode::class);
}

app/Episode.php

public function bestComment() {
    return $this->belongsToMany(Rating::class, 'comments', 'id')->orderBy('id', 'asc')->limit(1);
}

app/Http/Controllers/VideosController.php

public function index() {
    $videos = Videos::query();

    $videos->with('episodes');

    return view('videos.index')->with('videos', $videos->paginate(4));
}

resources/views/videos/index.blade.php

@foreach($videos as $video)
    
        {{ $video->title }}
        Best comment rating: {{ best_comment($video, 'name') }}
    
@endforeach

With my solution there are many queries. What's the best way to print the best rated comment?

Laravel Песочница

1 Ответ

0 голосов
/ 06 августа 2020

Это не самое оптимальное решение, но оно должно работать.

Сначала получите идентификаторы Video моделей из объекта разбивки на страницы:

$ids = $videos->getCollection()->pluck('id');

Затем используйте их, чтобы присоединиться к другим таблицам, группируя по видео и выбирая ID с наивысшим рейтингом. Возможно, вам придется настроить это, если у вас есть другие столбцы в вашей рейтинговой таблице, то есть вы можете ранжировать их лучше, чем с помощью их первичного ключа.

$videoToRatingMap = Videos::query()
    ->whereIn('id', $ids)
    ->join('episodes', 'episodes.video_id', '=', 'videos.id')
    ->join('comments', 'comments.episode_id ', '=', 'episodes.id')
    ->join('ratings', 'ratings.id', '=', 'comments.rating_id')
    ->groupBy('videos.id')
    ->select('videos.id')
    ->selectRaw('max(ratings.id) as rating_id')
    ->get();

Это даст вам карту видео по идентификатору и комментарий с наивысшим рейтингом.

Это не даст вам названия рейтингов, однако это можно сделать в отдельном запросе:

$ratingNames = Rating::query()
    ->findMany($videoToRatingMap->pluck('rating_id'))
    ->pluck('name', 'id');

Затем преобразуйте карту рейтинга, чтобы включить names:

$videoToRatingMap->transform(function($video) use ($ratingNames){
    $video['rating_name'] = $ratingNames[$video['rating_id']];
    return $video;
})->keyBy('id');

Это даст вам коллекцию, привязанную к идентификаторам видео, которая также содержит идентификатор рейтинга и его имя.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...