查询Laravel嵌套关系[Laravel 6.x]

时间:2019-12-22 08:44:49

标签: laravel eloquent relationship

我在Laravel应用中有一个页面,我在其中获取类别并渴望加载该类别中的事件。工作正常。我现在想做的是获取类别,但是这次,基于用户选择的区域/位置获取事件。这些是我正在使用的模型;

1.Region Class

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Region extends Model
{
    /**
     * Get events within region
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */

    public function events()
    {
        return $this->hasMany(Event::class);
    }
}
  1. 类别类别

    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Category extends Model
    {
        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'category_name', 'description', 'type', 'slug'
        ];
    
        /**
         * Get all events that belong to a category
         *
         * @return Illuminate\Database\Eloquent\Relations\HasMany
         */
        public function events()
        {
            return $this->hasMany(Event::class)->where('start_date', '>=', today())->orderBy('start_date', 'asc');
        }
    }
    

3.Event

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
     /**
     * Get an event's category
     *
     * @return Illuminate\Database\Eloquent\Relations\BelongsTo;
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * Get region of event
     *
     * @return [type] [description]
     */
    public function region()
    {
        return $this->belongsTo(Region::class);
    }
}

这是返回带有事件的类别的查询;

if (session()->has('region')) {
            $region_name = session()->get('region');

            $region = Region::where('region_name', $region_name)->firstOrFail();

            $categories = Category::withCount('events')
                                ->with('events')
                                ->whereHas('events', function (Builder $query) use ($region) {
                                    $query->where('region_id', $region->id);
                                })
                                ->orderBy('events_count', 'desc')
                                ->take(5)
                                ->get();
}

摘要:我想获取用户所选位置的事件的前5个类别。

预先感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

尝试使用此类别查询:

$categories = Category::with(['events' => function ($query) use ($region) {
    $query->where('region_id', $region->id);
}])->take(5)->get();

检查documentation on restraining eager loads

答案 1 :(得分:0)

您是否看过hasManyThrough关系? https://laravel.com/docs/5.8/eloquent-relationships#has-many-through

如果您通过Region类为Categories模型提供了许多Event,则可以这样做:

public function categories()
{
    return $this->hasManyThrough('App\Category', 'App\Event');
}

您应该可以拨打电话:

$region->categories;

应该返回所有具有该地区事件的类别。然后,您可以急于在每个类别中加载事件,按事件数排序,并在输出到视图之前采用前5个事件。

替代

一种替代方法是,简单地获取region_id为选定区域的所有事件,并为类别添加groupBy

$eventsByCategory = Event::where('region_id', $selectedRegion)->groupBy('category_id);

然后将事件按类别分组后,您可以按计数排序并排在前5名。

$eventsByCategory->sort()->take(5);

旁注:

对于类别模型上的事件关系,我会格外小心。我认为将where添加到返回值将返回Builder而不是Relation的实例,这意味着您可能无法利用某些关系功能。 我建议您查看Event模型上的作用域,以便可以根据过去发生事件的频率在全局或本地应用。