2016-12-28 20 views
2

私は "候補" Eloquentモデルにgeolocation属性を追加しようとしています。彼らの所在地に基づいて候補者を探したい。たとえば、サンフランシスコから20マイル以内の候補者をすべて見つけます。私のEloquentモデルは、候補者の場所をデータベースに格納するためにどのように見えるべきですか?Laravel 5でジオロケーションをクエリするにはどうすればよいですか?

候補者の場所に基づいて候補者をクエリするにはどうすればよいですか?私はLaravel 5.3を使用しています。

答えて

4

個人的には、これまで緯度と経度の座標を格納してこれを達成しました。

Haversine formulaと呼ばれるものを使用して、指定された座標のセットとあなたの場合は候補のセットとの間の "カラスの飛行"距離を計算することができます。

このようなクエリの例を次に示します。これは、例えば、「37、-122座標に対して半径25マイル以内の最も近い20の位置」を計算する。

SELECT id, (3959 * acos(cos(radians(37)) * cos(radians(lat)) 
* cos(radians(lng) - radians(-122)) + sin(radians(37)) * sin(radians(lat)))) AS distance 
FROM markers 
HAVING distance < 25 
ORDER BY distance 
LIMIT 0 , 20; 

元々見つかったhere

候補モデルに緯度/経度を追加すると、これはあなたのニーズに合わせて簡単に適応できます。

SELECT *, (3959 * acos(cos(radians(37)) * cos(radians(lat)) 
* cos(radians(lng) - radians(-122)) + sin(radians(37)) * sin(radians(lat)))) AS distance 
FROM candidates 
ORDER BY distance 
LIMIT 0, 20; 

おそらく、これをいくつかの種類のクエリスコープとして実装できます。 (試験および最小入力サニタイズを有していない)

public function scopeClosestTo($query, $lat, $lng) 
{ 
    return $query->orderByRaw(
     '(3959 * acos(cos(radians(' . floatval($lat) . ')) * cos(radians(lat)) * cos(radians(lng) - radians(' . floatval($lng) . ')) + sin(radians(' . intval($lat) . ')) * sin(radians(lat)))) ASC' 
    ); 
} 

注: 3959この場合には、マイル地球の半径であり、式は、マイルの距離を計算します。距離をキロメートルにする必要がある場合は、3959を6371に変更してください。コメントでこれを指摘してくれた@Lionelに感謝します。

+2

3959は地球の半径(マイル)です。 KMで必要な場合は、6371(KM)に変更するだけです。 –

+0

興味深いです。それは難解だと思われますが、これを行う最良の方法です!私たちにいくつかのSQL文を作成させなければならない。 Googleマップには同様のSQLクエリを書くチュートリアルもあります:https://developers.google.com/maps/articles/phpsqlsearch_v3ありがとう –

+0

Googleマップのチュートリアルは、もともとHaversineのSQL版が見つかった場所です数式:問題ありません。 – Jonathon

関連する問題