我希望为我的“候选人”Eloquent模型添加一个地理位置属性。我想根据他们的位置查找候选人。例如,查找距离旧金山20英里以内的所有候选人。我的Eloquent模型应该如何才能在数据库中存储候选人的位置?
我如何基于候选人的位置查询候选人?我正在使用Laravel 5.3。
我希望为我的“候选人”Eloquent模型添加一个地理位置属性。我想根据他们的位置查找候选人。例如,查找距离旧金山20英里以内的所有候选人。我的Eloquent模型应该如何才能在数据库中存储候选人的位置?
我如何基于候选人的位置查询候选人?我正在使用Laravel 5.3。
个人而言,我之前通过存储一组纬度和经度坐标来实现这一点。
您可以使用称为哈弗赛恩公式计算特定坐标集(在您的情况下是候选集)之间的“直线距离”。
以下是这样一个查询的示例。例如,此查询计算“半径为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在评论中指出了这一点。