在Laravel 5中如何通过地理位置信息进行查询?

5

我希望为我的“候选人”Eloquent模型添加一个地理位置属性。我想根据他们的位置查找候选人。例如,查找距离旧金山20英里以内的所有候选人。我的Eloquent模型应该如何才能在数据库中存储候选人的位置?

我如何基于候选人的位置查询候选人?我正在使用Laravel 5.3。

1个回答

5

个人而言,我之前通过存储一组纬度和经度坐标来实现这一点。

您可以使用称为哈弗赛恩公式计算特定坐标集(在您的情况下是候选集)之间的“直线距离”。

以下是这样一个查询的示例。例如,此查询计算“半径为25英里内距离37, -122坐标最接近的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;

本文最初在这里发现。

如果您将经纬度添加到候选人模型中,这很容易适应您的需求。

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是地球半径(以英里为单位)。如果您需要使用公里,请将其更改为6371(公里)。 - Lionel Chan
好的,很有趣。看起来很玄学,但似乎这是最好的方法!必须编写一些SQL语句。Google地图也有一个教程,在那里他们编写了类似的SQL查询:https://developers.google.com/maps/articles/phpsqlsearch_v3 谢谢 - Connor Leech
1
是的,Google Maps教程是我最初找到Haversine公式SQL版本的地方 :) 没问题。 - Jonathon
这在大表中如何运作?有人测试过吗? - AngelGris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接