猿问

如何在laravel中按其关系对集合进行排序

我的酒店有一个复杂的过滤器,最后我有一个集合,我想通过它的嵌套关系对父关系进行排序,所以这里我有如下:


  public function resultFilter($from_date, $to_date, $bed_count, $city_id, $stars, $type_id, $hits, $price, $accommodation_name, $is_recommended, $start_price, $end_price, $has_discount, $facility_id)

    {

//        $data = QueryBuilder::for(Accommodation::class)

//            ->allowedFilters(['city_id','grade_stars','accommodation_type_id'])

//            ->allowedIncludes('gallery')

//            ->when($bed_count, function ($q, $bed_count) {

//                $q->with([

//                    'accommodationRoomsLimited' => function ($q) use ($bed_count) {

//                        $q->where('bed_count', $bed_count);

//                    }

//                ]);

//            })

//            ->paginate(10);

//        ->get();

//            ->orderBy('hits','DESC')->paginate(10);

        $data = Accommodation::with(['city','accommodationFacilities', 'gallery', 'accommodationRoomsLimited.discount', 'accommodationRoomsLimited', 'accommodationRoomsLimited.roomPricingHistorySearch' => function ($query) use ($from_date, $to_date) {

            $query->whereDate('from_date', '<=', $from_date);

            $query->whereDate('to_date', '>=', $to_date);

        }])->when($bed_count, function ($q, $bed_count) {

                $q->whereHas('accommodationRoomsLimited', function($query) use ($bed_count) {

                    $query->where('bed_count', $bed_count);

                });

        })->when($accommodation_name, function ($query, $accommodation_name) {

            $query->where('name', 'like', $accommodation_name);

        })

因此,如果您阅读代码,我添加了 sales_price,如果请求中存在 $price,我想按它对 $data 进行排序。所以在一个短期问题中,我想在上面的这个查询中按 sales_price 对 $data 进行排序。


注意 :此过滤器可能会变得更复杂,因此任何其他最佳实践或更好的方法,如 spatie 查询构建器或本地范围,尽管我都尝试过,但它们有自己的限制,我们将不胜感激


MYYA
浏览 195回答 1
1回答

绝地无双

我以前也遇到过这个问题。看来我需要先解释一下急切加载。您不能订购eager loading,您可以在获取数据后订购。因为&nbsp;急切加载会拆分连接查询以获得更好的性能。例如,您查询accomodation并与城市有关系。该accomodation表有 1000 条记录,而该city表有 10.000 条记录。假设预加载的最大 id 为 250,唯一city_id来自accomodation表的为 780。将生成 5 个查询。$data&nbsp;=&nbsp;Accomodation::with('city')->get();select * from accomodationselect * from city where id in [unique_id_1 - unique_id_250]select * from city where id in [unique_id_251 - unique_id_500]select * from city where id in [unique_id_501 - unique_id_750]select * from city where id in [unique_id_751 - unique_id_780]city然后 laravel 将完成通过查询结果创建关系的工作。通过这种方法,您将解决N+1连接查询的问题,因此它应该更快。然后假设您想accomodation通过查询生成器中city.name的方法进行排序。with让我们以第三个查询为例。$data = Accomodation::with([&nbsp; &nbsp; 'city' => function($q) { return $q->orderBy('name'); },])->get();查询将是:select * from city where id in [unique_id_251 - unique_id_500] order by name城市结果将被排序,但 laravel 会以相同的方式读取它。它将 accomodation首先创建,然后将其与city查询相关联。所以来自的订单city不会影响accomodation订单。那么如何订购呢?我找到了几种方法来实现这一目标。加入查询。这是最简单的方法,但会使查询变慢。如果您的数据不是很大并且连接查询不会影响您的性能。也许 0.003 秒的性能提升并不值得你花 8 个小时。sortBy在收藏功能中。您可以使用集合中的方法对其进行排序。例如,如果你想订购accomodation基于country.namefromcity关系,这个脚本会帮助你。$data = Accomodation::with('city.country')->get();$data->sortBy(function($item) {&nbsp; &nbsp; return $item->city->country->name;});展平集合。此方法将尝试展平集合,因此结果将类似于join查询然后对其进行排序。您可以使用map集合中的方法。我确实相信所有过滤器和可搜索的字符串都应该包含在数据中。$data->map(function($item) {&nbsp; &nbsp; return [&nbsp; &nbsp; &nbsp; 'city_name' => $city->name,&nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; all_searchable_data,&nbsp; &nbsp; &nbsp; all_shareable_data,&nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; ];&nbsp; })->sortBy('key1);如果可能,更改急切加载方向。您可以通过更改基本型号订购它。例如,您改用city它accomodation来订购它city.name$data = City::with('accomodation')->orderBy('name')->get();最后,如果您的数据很少更改(例如每 2 小时一次),您可能会考虑使用缓存。您只需每 2 小时使缓存失效并创建新缓存。根据我的经验,如果数据很大,缓存总是比查询数据库快。您只需要知道间隔或event使缓存无效。您选择的任何内容都取决于您。但是请记住这一点,当您使用来自 laravel 的集合处理批量数据时,它可能比从数据库中查询要慢。也许是因为 PHP 的性能。对我来说,最好的方法是使用eager loadingthen ->map()it then cacheit。为什么我需要map先缓存它?原因是,通过选择某些属性会减小缓存大小。然后你将获得更多的性能。我可以说它会产生更易读、更漂亮的代码。奖金 这就是我这样做的方式。$data = Cache::remember("accomodation", 10, function() {&nbsp; $data = Accommodation::with([&nbsp; &nbsp; 'city',&nbsp; &nbsp; ...&nbsp; &nbsp; ])&nbsp; &nbsp; ->get();&nbsp; return $data->map(function($item) {&nbsp; &nbsp; return [&nbsp; &nbsp; &nbsp; 'city_name' => $item->city->name,&nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; all_additional_data,&nbsp; &nbsp; &nbsp; all_searchable_data,&nbsp; &nbsp; &nbsp; all_shareable_data,&nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; ];&nbsp; });}return $data->search(function($item) use ($searchKey, $searchAnnotiation, $searchValue) {&nbsp; switch ($searchAnnotiation) {&nbsp; &nbsp; case '>':&nbsp; &nbsp; &nbsp; return $item[$searchKey] > $searchValue;&nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; case '<':&nbsp; &nbsp; &nbsp; return $item[$searchKey] < $searchValue;&nbsp; &nbsp; &nbsp; break;&nbsp; }})->sortBy($sortKey)->paginate();缓存将保存处理后的数据。因此所需的执行时间是从缓存中获取数据、过滤数据并对其进行排序。然后将其转换为分页。您可以在这些流程中设置任何额外的缓存以获得更快的结果。$data->paginate()通过paginate为Collection.
随时随地看视频慕课网APP
我要回答