Laravel按用户坐标排序获取附近餐厅的功能实现问询
实现按用户坐标距离排序餐厅的方案
步骤1:修改函数参数,接收用户坐标
先给get_restaurants方法新增用户纬度($user_lat)和经度($user_lng)参数,让API调用时能传入这两个坐标值。
步骤2:在查询中计算距离并排序
利用MySQL的地理函数计算餐厅与用户的直线距离,再按距离由近到远排序。推荐用ST_Distance_Sphere(MySQL 5.7+支持,计算精度高,返回单位为米),如果是旧版本MySQL则用Haversine公式兼容。
修改后的完整代码
<?php namespace App\CentralLogics; use App\Models\Restaurant; use App\Models\OrderTransaction; class RestaurantLogic { // 新增$user_lat和$user_lng参数 public static function get_restaurants($zone_id, $filter, $user_lat, $user_lng, $limit = 10, $offset = 1, $type='all') { $paginator = Restaurant:: withOpen() ->with(['discount'=>function($q){ return $q->validate(); }])->whereIn('zone_id', $zone_id) ->when($filter=='delivery', function($q){ return $q->delivery(); }) ->when($filter=='take_away', function($q){ return $q->takeaway(); }) ->Active() ->type($type) // 根据是否传入坐标切换排序逻辑 ->when(isset($user_lat) && isset($user_lng), function($q) use ($user_lat, $user_lng) { // 计算距离(米)并作为distance字段返回,按距离升序排序 return $q->selectRaw('*, ST_Distance_Sphere(point(longitude, latitude), point(?, ?)) as distance', [$user_lng, $user_lat]) ->orderBy('distance', 'asc'); }, function($q) { // 未传入坐标时保留原有排序逻辑 return $q->orderBy('open', 'desc'); }) ->paginate($limit, ['*'], 'page', $offset); return [ 'total_size' => $paginator->total(), 'limit' => $limit, 'offset' => $offset, 'restaurants' => $paginator->items() ]; } }
可选:旧版本MySQL兼容方案(Haversine公式)
如果你的MySQL版本低于5.7,把上面的selectRaw替换为以下代码(计算结果为公里,地球半径取6371公里):
selectRaw('*, 6371 * acos(cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) + sin(radians(?)) * sin(radians(latitude))) as distance', [$user_lat, $user_lng, $user_lat])
注意事项
- 确保
Restaurant对应的数据库表存在latitude和longitude字段,推荐字段类型为DECIMAL(10,8)。 - 调用该方法的API接口需要同步传入
user_lat和user_lng参数。 - 返回的餐厅数据会新增
distance字段,前端可直接用该值展示距离信息。
内容的提问来源于stack exchange,提问作者amaan
相关产品推荐
相关产品推荐

