首先,我想向您展示当前的数据库结构。有三个表:
菜(身份证,姓名)
位置(ID,名称,坐标(要点))
dish_location(location_id,dish_id)
现在,我想实现一个API,该API获取用户的位置(纬度,经度),并返回按距离(以公里为单位)排序的菜肴清单。我已经有一种方法需要两个纬度和两个经度并给我距离。但是我相信您可以向我展示一种方法,这是直接在MySQL查询中执行此操作的性能更高的方法。
另外:我想在API中执行“加载更多”功能。因此,我将已经收到的物品计数,或者在这种情况下如何解决?
我正在将其用于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()
函数计算我们可以对结果进行排序的距离。Laravel的paginate()
方法使用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
包装Collection
模型的Laravel的实例。如果我们将结果传递给视图,请按照以下方法在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请求来加载结果。只需确保在请求数据的参数中传递当前页面+ 1page
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句