laravel排序失效的解決辦法:1、通過「$query->whereIn(...)」查詢資料;2、通過filter過濾資料;3、設定排序好的資料為「$data = $scoutModelsLists;」。
本文操作環境:Windows7系統、Laravel5.8版、Dell G3電腦。
如何解決laravel排序失效問題?
Laravel 5.8+scout7.0 使用 orderBy 排序失效解決方案
最近在使用 elasticSearch6.2.4 做搜尋時發現,排序欄位失效,所以在這記錄下
先看下解決方案,話不多說,直接上程式碼
$list = Article::search($words)->orderBy('created_at','desc')->paginateRaw(10)->toArray(); $results = $list['data']; if ($results['hits']['total'] === 0) { return $this->model->newCollection(); } $builder =new Builder(new static(),$this->model->newModelQuery()); $keys = collect($results['hits']['hits'])->pluck('_id')->values()->all(); $query = $this->newQuery(); if ($builder->queryCallback) { call_user_func($builder->queryCallback, $query); } //查詢資料 $scoutModelsLists = $query->whereIn( $this->model->qualifyColumn($this->model->getKeyName()), $keys )->orderBy('created_at','desc')->get(); //過濾資料 $scoutModelsLists->filter(function () use ($keys) { return in_array($this->model->getKey(), $keys); }); //這裡為最終排序好的資料 $data = $scoutModelsLists;
問題分析
原來使用的查詢語句為
$list = Article::search($words)->orderBy('created_at','desc')->paginate(10)->toArray();
上面查詢語句雖然設定了排序欄位,但是最終輸出的時候卻沒有排序,經分析,在 ES 搜尋結果裡面的確是排了序,但最終輸出時,ES 資料結構轉化為集合時,並未加上排序欄位
程式碼分析
檔案 1: /vendor/laravel/scout/src/builder.php 約 261 行 - 305 行
仔細觀察這個檔案會有兩個方法 paginate、paginateRaw ,前一個返回 laravel 集合,後一個返回 es 的原生查詢結構,
這兩者程式碼的不同點在於這塊
$results = $this->model->newCollection($engine->map( $this, $rawResults = $engine->paginate($this, $perPage, $page), $this->model )->all());
檔案 2:vendor/tamayo/laravel-scout-elastic/src/ElasticsearchEngine.php 211 行,map 方法,因為這裡我們使用的是 ES 引擎,如果使用別的,可能有所不同,程式碼:
public function map(Builder $builder, $results, $model) { //無資料返回空集合 if ($results['hits']['total'] === 0) { return $model->newCollection(); } //獲取所有鍵為_id的ES資料 //$keys = collect($results['hits']['hits'])->pluck('_id')->values()->all(); //轉化ES資料並過濾 return $model->getScoutModelsByIds( $builder, $keys )->filter(function ($model) use ($keys) { return in_array($model->getScoutKey(), $keys); }); }
從程式碼看來,es 搜尋出來有資料,則轉化並過濾一下返回符合條件的集合,不滿足直接返回空
檔案 3: /vendor/laravel/scout/src/Searchable.php 約 171 行 getScoutModelsByIds 方法,程式碼
public function getScoutModelsByIds(Builder $builder, array $ids) { //加入軟刪除 $query = static::usesSoftDelete() ? $this->withTrashed() : $this->newQuery(); if ($builder->queryCallback) { call_user_func($builder->queryCallback, $query); } // 重點這裡,自改程式碼 // return $query->whereIn( // $this->getScoutKeyName(), $ids // )->orderBy('orderBy','desc')->get(); //官方程式碼 return $query->whereIn( $this->getScoutKeyName(), $ids )->get(); }
這個檔案是重點,主要是這裡最後返回的時候並沒有加上 orderBy 排序欄位,所以最後輸出時雖然 es 排序了,這裡又重置了,為防止改元件後其他地方無法更新,所以在最後返回資料時加了排序處理,方案參考文章開頭。
暫時告一段落,空了再完善。
(推薦)
以上就是如何解決laravel排序失效問題的詳細內容,更多請關注TW511.COM其它相關文章!