已知数据库中有很多位置经纬度坐标 lng 、 lat,将这些位置按照距已知位置A(坐标 $lng 、$lat)的距离升序排序
数据量小直接用SQL查询即可
升序排序示例:distance 是计算出来的距离单位是公里
$sql = "select *, ACOS(SIN(( $lat * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS(( $lat * 3.1415) / 180 ) * COS((lat * 3.1415) / 180 ) *COS(( $lng * 3.1415) / 180 - (lng * 3.1415) / 180 ) ) * 6380 as distance from `store` where (`status` = '1') and `type_id` = '1' order by `distance` asc limit 30 offset 30";
升序排序示例:distance 是计算出来的距离单位是公里
$distance = "ACOS(SIN(( $lat * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS(( $lat* 3.1415) / 180 ) * COS((lat * 3.1415) / 180 ) *COS(( $lng* 3.1415) / 180 - (lng * 3.1415) / 180 ) ) * 6380";
$list = $this->model->select('*')->addSelect(\DB::raw($distance . ' as distance'))->orderBy('distance', 'ASC')->get()->toArray();
dd($list);
数据量大的情况下要考虑elasticssearch、Redis、MongoDB 等第三方存储,性能更佳。
1、创建Redis数据源:通过 geoAdd 方法将数据库中的位置坐标存储到redis中
geoadd 方法:用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。
Redis::geoAdd($key, $lng, $lat, $member);
2、获取排序好的位置列表
georadius 方法:以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
public static function geoRadius($key, $lng, $lat, int $distance = 500, string $unit = 'km', array $options = ['WITHDIST', 'ASC'])
{
return Redis::geoRadius($key, $lng, $lat, $distance, $unit, $options);
}