2017-03-15 118 views
0

我知道這已被問了很多次。 但我沒有想到根據我的需要。如何查詢兩個座標之間的距離與雄辯

我需要從另一個用戶查詢最近的用戶。 基本上,我有一個users表這個表有one to oneusers_locations表有關的緯度和經度字段。

所以我見過這個 https://laravel.io/forum/04-23-2014-convert-this-geolocation-query-to-query-builder-for?page=1 這可能是最好的解決方案。

但我的基本的查詢是:

\App\Model\User::whereNotIn('id', $ids) 
       ->where('status', 1) 
       ->whereHas('user_location', function($q) use ($lat, $lng, $radius) { 
        /** This is where I'm stuck to write the query **/ 
      })->select('id', 'firstname') 
       ->get(); 

我不知道如何實現在這種情況下的解決方案。

預先感謝您的幫助

編輯 更清楚: 我需要是在5公里半徑內的用戶。

+0

見:http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula – Serge

+0

嗯,是謝謝你,但我已經有這個函數,我需要用MySQL來做這件事,因爲我有超過50000個用戶,在這種情況下,我應該得到所有這些用戶en計算距離並最終保持足夠接近的所有用戶,並且這可能需要太多資源.. – KeizerBridge

+0

您應該真正使用空間索引,但是您可以直接在查詢中執行此操作,例如:http: //sackoverflow.com/questions/8994718/mysql-longitude-and-latitude-query-for-other-rows-within-x-mile-radius – Serge

回答

2

我找到了解決方案,感謝EddyTheDove和Ohgodwhy。

因此,這是它:

\App\Model\User::whereNotIn('id', $ids) 
      ->where('status', 1) 
      ->whereHas('user_location', function($q) use ($radius, $coordinates) { 
        $q->isWithinMaxDistance($coordinates, $radius); 
     })->select('id', 'firstname') 
      ->get(); 

在我UserLocation型號我有這個局部範圍

public function scopeIsWithinMaxDistance($query, $coordinates, $radius = 5) { 

    $haversine = "(6371 * acos(cos(radians(" . $coordinates['latitude'] . ")) 
        * cos(radians(`latitude`)) 
        * cos(radians(`longitude`) 
        - radians(" . $coordinates['longitude'] . ")) 
        + sin(radians(" . $coordinates['latitude'] . ")) 
        * sin(radians(`latitude`))))"; 

    return $query->select('id', 'users_id', 'cities_id') 
       ->selectRaw("{$haversine} AS distance") 
       ->whereRaw("{$haversine} < ?", [$radius]); 
} 

原來答案由Ohgodwhy是在這裏: Haversine distance calculation between two points in Laravel

編輯

在MySQL存儲函數來執行它的另一種方式:

DELIMITER $$ 
DROP FUNCTION IF EXISTS haversine$$ 

CREATE FUNCTION haversine(
     lat1 FLOAT, lon1 FLOAT, 
     lat2 FLOAT, lon2 FLOAT 
    ) RETURNS FLOAT 
    NO SQL DETERMINISTIC 
    COMMENT 'Returns the distance in degrees on the Earth 
      between two known points of latitude and longitude' 
BEGIN 
    RETURN DEGREES(ACOS(
       COS(RADIANS(lat1)) * 
       COS(RADIANS(lat2)) * 
       COS(RADIANS(lon2) - RADIANS(lon1)) + 
       SIN(RADIANS(lat1)) * SIN(RADIANS(lat2)) 
      )); 
END$$ 

DELIMITER ; 

我乘以111.045的結果轉換成公里。 (我不知道,這個值是正確的,我發現很多人值不遠處的這一個,所以如果有人有關於它的精確度,它可能是不錯的)

原創文章:https://www.plumislandmedia.net/mysql/stored-function-haversine-distance-computation/

然後使用雄辯:

\App\Model\User::whereNotIn('id', $ids) 
     ->where('status', 1) 
     ->whereHas('user_location', function($q) use ($radius, $coordinates) { 
      $q->whereRaw("111.045*haversine(latitude, longitude, '{$coordinates['latitude']}', '{$coordinates['longitude']}') <= " . $radius]); 
    })->select('id', 'firstname') 
     ->get();