場景:後端需要根據使用者所在位置,擷取距離使用者附近的店鋪清單,并按距離遠近排序
在網上一番搜尋後,找到了這篇文章TP5 根據經緯度計算距離,排序+分頁,經過測試,總結出如下的代碼
PS:該方法擷取到的機關是米
/**
* 在資料庫中擷取所有店鋪,按距離使用者的遠近排序(預設升序
* 距離機關是米
* @param double $lat 緯度
* @param double $lng 經度
* @param string $order 排序方式(asc/升序,desc/降序
* @return array 傳回查詢的資料
*/
public function getDistanceByLatLng($lat, $lng, $order = 'asc')
{
// 資料庫表名
$database_name = 'test_table';
// 資料庫字段名 - 緯度
$field_lat = 'lat';
// 資料庫字段名 - 經度
$field_lng = 'lng';
return Db::table($database_name)
->field("*, (6378.138 * 2 * asin(sqrt(pow(sin(({$field_lat} * pi() / 180 - {$lat} * pi() / 180) / 2),2) + cos({$field_lat} * pi() / 180) * cos({$lat} * pi() / 180) * pow(sin(({$field_lng} * pi() / 180 - {$lng} * pi() / 180) / 2),2))) * 1000) as distance")
// 按距離升序排列(由近到遠
->order("distance {$order}")
->select();
}
實踐過程
首先在資料庫中建立表,結構如下
資料表名:
test_table
名 | 類型 | 備注 |
---|---|---|
id | int(255) | |
address | varchar(255) | 位址 |
lat | double | 緯度 |
lng | double | 經度 |
remark | varchar(255) | 備注 |
填充資料
以下資料已上傳到CSDN
id | address | lat | lng | remark |
---|---|---|---|---|
1 | 河南省鄭州市金水區農業快速路河南博物館 | 34.787258 | 113.672303 | |
2 | 河南省鄭州市金水區文博東路文博公園 | 34.787831 | 113.674265 | 在河南博物館旁邊,距離河南博物館很近 |
3 | 河南省鄭州市二七區二七路97号鄭州市人民公園 | 34.761103 | 113.662795 | |
4 | 河南省洛陽市洛龍區通衢路錦台廣場 | 34.596366 | 112.467488 | |
5 | 山東省德州市德城區新河路萬達廣場 | 37.429004 | 116.31163 | |
6 | 新疆維吾爾自治區烏魯木齊市沙依巴克區紫金公園 | 43.761815 | 87.458698 |
開始測試
// 使用者1的位置(河南省鄭州市金水區農業路河南省農業科學院
$lat = 34.788179;
$lng = 113.679335;
// 調用文章開頭的方法
$result = $this->getDistanceByLatLng($lat, $lng);
halt($result);
由圖可知,使用者1的左邊就是資料庫中的
文博公園
,再左邊就是資料庫中的
河南博物館
,是以列印結果中文博公園的位置應該比河南博物館的位置靠前,來看一下
運作結果和預期一樣,接下來再測試一次
假設使用者2在新疆,那麼列印結果中資料庫中新疆的位置應該會靠前,看代碼和結果
// 使用者2的位置(新疆維吾爾自治區阿克蘇地區阿克蘇市幸福中路幸福公園
$lat = 41.165831;
$lng = 80.278014;
$result = $this->getDistanceByLatLng($lat, $lng);
halt($result);