Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да сортирате резултатите от заявката по разстояние в Laravel QueryBuilder / MySQL Spatial пакет?

Първо, нека да разгледаме как да направите това с основния конструктор на заявки. След това ще обсъдим как да изпълним тази заявка с моделите Eloquent:

function paginateDishesFromPoint(Point $point, $pageSize) 
{
    $distanceField = "ST_Distance_Sphere(locations.coordinates, "
        . "ST_GeomFromText('{$point->toWKT()}') AS distance"; 

    return DB::table('dishes') 
        ->select('dishes.*', DB::raw($distanceField))
        ->join('dish_locations', 'dish_locations.dish_id', '=', 'dishes.id')
        ->join('locations', 'locations.id', '=', 'dish_locations.location_id')
        ->orderBy('distance') 
        ->paginate($pageSize);
}

ST_Distance_Sphere() функцията изчислява разстояние, по което можем да сортираме резултатите. paginate() на Laravel методът извършва автоматично разделяне на страници вместо нас с помощта на page параметър, предаден през URL адреса на заявката. Прочетете документите за пагинация за повече информация. С функцията по-горе можем да извлечем набор от резултати с пагинация, както следва:

$point = new Point($latitude, $longitude); 
$sortedDishes = paginateDishesFromPoint($point, 15); 

...където Point е Grimzy\LaravelMysqlSpatial\Types\Point клас от пакета ние използваме, и 15 е броят на резултатите на страница.

Сега, нека се опитаме да направим това с моделите Eloquent. Ще използваме локален обхват на заявката за да капсулирате логиката, необходима за създаване на частта от заявката, която изпълнява подреждането:

class Dish extends Model 
{
    ...

    public function locations() 
    {
        return $this->belongsToMany(App\Location::class);
    }

    public function scopeOrderByDistanceFrom($query, Point $point) 
    {
        $relation = $this->locations();
        $locationsTable = $relation->getRelated()->getTable();
        $distanceField = "ST_Distance_Sphere($locationsTable.coordinates, "
        . "ST_GeomFromText('{$point->toWKT()}') AS distance";

        return $query
            ->select($this->getTable() . '.*', DB::raw($distanceField))
            ->join(
                $relation->getTable(), 
                $relation->getQualifiedForeignKeyName(), 
                '=', 
                $relation->getQualifiedParentKeyName()
            )
            ->join(
                $locationsTable,
                $relation->getRelated()->getQualifiedKeyName(),
                '=', 
                $relation->getQualifiedRelatedKeyName()
            )
            ->orderBy('distance');
    }
}

Тази реализация използва метаданни за моделите, за да добави имената на таблицата и полетата към заявката, така че не е необходимо да актуализираме този метод, ако се променят. Сега можем да извлечем поръчания комплект с помощта на модела:

$point = new Point($latitude, $longitude); 
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);

$sortedDishes е екземпляр на LengthAwarePaginator на Laravel който обвива Collection на моделите. Ако предадем резултатите на изглед, ето как да ги покажем в Blade шаблон:

<ul>
    @foreach($sortedDishes as $dish) 
        <li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
    @endforeach
</ul>

<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>

Както е показано по-горе, пагинаторът предоставя удобни методи които можем да използваме за лесно придвижване между страниците с резултати.

Като алтернатива можем да използваме AJAX заявки за зареждане на резултатите. Просто не забравяйте да предадете текущата страница + 1 в page параметър на данните за заявката.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL инжекция от LIKE оператор

  2. Обяснете поведението при картографиране на автоматично увеличена съставна идентификационна последователност с Hibernate

  3. Какво може да накара mysql db read да върне остарели данни

  4. Множество маси се съединяват в релси

  5. 'fetch' в PDO получава само един резултат