如何通过类方法返回的值对Laravel Eloquent搜索查询排序结果?

时间:2016-06-07 18:42:27

标签: php laravel eloquent

我正在为Laravel 5.2应用程序构建一些搜索功能。在我的模型中,Event有一个Location,它由纬度和经度值组成。 Location类有一个计算距离$this->distanceTo($that)的方法。

我希望能够通过各种条件(关键字,类别等)搜索我的事件,然后按距离将结果排序到指定点。所以我的路线看起来像这样:

$query = App\Event::query();

if (Input::has('keyword')) {
    $query = $query->where('name', 'like', '%'.Input::get('keyword').'%');
}

if (Input::has('category')) {
    $query = $query->where('category_id', Input::get('category'));
}

$events = $query->get();

在我看来,我需要运行此查询,然后对它返回的集合执行排序。但如果有一种方法可以将排序合并到查询本身中,那么它可能会表现得更好。有没有办法做到这一点?

如果没有,那么我仍然需要弄清楚如何对返回的集合执行排序。我知道有一个sortBy()方法可用于集合,但是当我需要按$eventFromCollection->location()->distanceTo($searchLocation)排序时,我不确定如何将它们组合在一起。对此有何指导?

1 个答案:

答案 0 :(得分:1)

我构建了一个类似的功能,并将分享我的经验。

有几种不同的方法可以做到这一点:

  1. 在SQL中进行计算。这需要使用Haversine formula。这是一个SQL Example。你可以找到很多例子,搜索“Geo distance sql”
  2. 您可以使用PHP(见下文)
  3. 来完成
  4. 谷歌Distance Matrix API。 (如果速度和性能不是问题,并且您准备每天支付更高的查询费用,请使用此方法)
  5. 使用托管搜索作为内置地理距离的服务。(见下文)
  6. 我会忽略#1和#3,因为你可以很容易地找到那些“如何做”。

    <强> 2。使用PHP:

    您必须在sql操作后对结果进行排序。你可以使用这样的东西:

    不得在生产中使用

    验证或错误处理

    public function distance($lat1, $lon1, $lat2, $lon2, $unit = 'K') {
    
        $theta = $lon1 - $lon2;
    
        $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    
        $dist = acos($dist);
    
        $dist = rad2deg($dist);
    
        $miles = $dist * 60 * 1.1515;
    
        $unit = strtoupper($unit);
    
        if ($unit == "K") {
    
            return round(($miles * 1.609344), 2);
    
        } else if ($unit == "N") {
    
            return round(($miles * 0.8684), 2);
    
        } else {
    
            return round($miles, 2);
    
        }
    
    
    }
    

    这将为您提供两组坐标之间的距离。迭代DB中的结果并使用它对它们进行排序。

    <强> 2。使用托管搜索服务:

    Algolia对于“搜索”来说是一个非常好的解决方案。它有一个Laravel package可以轻松实现,并且内置Geo search功能。

    我根据要求使用2,3和4的组合。