Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak posortować wyniki zapytań według odległości w pakiecie Laravel QueryBuilder / MySQL Spatial?

Najpierw przyjrzyjmy się, jak to zrobić za pomocą podstawowego konstruktora zapytań. Następnie omówimy, jak wykonać to zapytanie za pomocą modeli Eloquent:

Funkcja
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() funkcja oblicza odległość, według której możemy sortować wyniki. paginate() Laravela metoda wykonuje dla nas automatyczną paginację za pomocą page parametr przekazany przez adres URL żądania. Przeczytaj dokumentację podziału na strony po więcej informacji. Za pomocą powyższej funkcji możemy pobrać zestaw wyników z podziałem na strony w następujący sposób:

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

...gdzie Point to Grimzy\LaravelMysqlSpatial\Types\Point klasa z pakietu używamy i 15 to liczba wyników na stronie.

Teraz spróbujmy to zrobić z modelami Eloquent. Użyjemy lokalnego zakresu zapytań aby zawrzeć logikę potrzebną do utworzenia części zapytania, która wykonuje kolejność:

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');
    }
}

Ta implementacja używa metadanych w modelach, aby dodać nazwy tabel i pól do zapytania, więc nie musimy aktualizować tej metody, jeśli ulegną zmianie. Teraz możemy pobrać zamówiony zestaw za pomocą modelu:

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

$sortedDishes jest instancją LengthAwarePaginator Laravela która otacza Collection modeli. Jeśli przekażemy wyniki do widoku, oto jak wyświetlić je w szablonie Blade:

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

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

Jak pokazano powyżej, paginator zapewnia wygodne metody które możemy wykorzystać do łatwego przemieszczania się między stronami wyników.

Alternatywnie możemy użyć żądań AJAX do załadowania wyników. Pamiętaj tylko, aby przekazać bieżącą stronę + 1 na page parametr danych żądania.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. relacja wiele-do-wielu w doktrynie

  2. Wydajność MYSQL jest niska przy użyciu sortowania plików

  3. Dlaczego mój wynik jest duplikowany podczas korzystania z podzapytania?

  4. Jak odjąć godziny od daty i godziny w MySQL?

  5. Najlepsze praktyki dotyczące wyświetlania wyników wyszukiwania z powiązanymi fragmentami tekstu z rzeczywistych wyników