【问题标题】:figured out spatial user search, but how do i order it by distance? (php laravel mysql)想出了空间用户搜索,但我如何按距离排序? (php laravel mysql)
【发布时间】:2017-12-17 12:04:13
【问题描述】:

经过一夜的折腾,我设法让用户按距离进行搜索!我多年来一直想实现的目标。但是我还有另一个问题。我无法按距离对它们进行排序。

我有一个用户表。每个用户都有一个“国家”、“州”、“邮政编码”和“郊区”。

我还有一个包含以下字段的位置表。

“国家”、“州”、“邮政编码”和“郊区”、经度、纬度

我设法破解了一个按距离顺序返回所有地点的查询。但现在我想按距离顺序返回该郊区、邮政编码、州和国家/地区的所有用户。

这是我目前的代码,我不知道如何修改它。

//spatial queries

                static function cmp($user1, $user2)
                {
                    global $places;

                    foreach($places as $place)
                    {
                        if(($place->country == $user1->country) && ($place->suburb == $user1->suburb) && ($place->state == $user1->state))
                        {
                             return true;
                        } 
                        if(($place->country == $user2->country) && ($place->suburb == $user2->suburb) && ($place->state == $user2->state))
                        {
                             return false;
                        } 
                    }
                    return false;
                }

public function search()
{
    if (Auth::guest()) 
    {
        return Redirect::guest('/');
    }
    else
    {
        if ( Session::token() !== request( '_token' ) ) {
            return Response::json( array(
                'searcherror' => 'Invalid Authorization Token'
            ) );
        }





        //identify the right query (make sure later: if you arent what they are looking for, they dont show up. If you are blocked, they dont show up)


        if(request('country') && request('lfmin') && request('lfmax'))
        {

            //main requirements exist
            if(!request('state') && !request('suburb') && !request('postcode') && request('distance'))
            {   





                //spatial queries

                //$circle_radius = 3959; //miles
                $circle_radius = 6371; //kms
                $max_distance = request('distance');
                $lat = Auth::user()->getLoc()->latitude;
                $lng = Auth::user()->getLoc()->longitude;

                //get all nearby places
                 $places = DB::select(
                               'SELECT * FROM
                                    (SELECT id, country, suburb, state, latitude, longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
                                    cos(radians(longitude) - radians(' . $lng . ')) +
                                    sin(radians(' . $lat . ')) * sin(radians(latitude))))
                                    AS distance
                                    FROM places) AS distances
                                WHERE distance < ' . $max_distance . '
                                ORDER BY distance;
                            ');


                 /*

                $result = User::contains('country', $places->country)
                ->contains('state', $places->state)
                ->contains('postcode', $places->postcode)
                ->contains('suburb', $places->suburb)
                ->get();
                */

                $countryarray = [];
                $suburbarray = [];
                $statearray = [];

                foreach($places as $place)
                {
                    //get country array
                    //get state array
                    //get suburb array
                    array_push($countryarray, $place->country);
                    array_push($suburbarray, $place->suburb);
                    array_push($statearray, $place->state);
                }

                $places = (object)$places;


                $users = User::whereIn('suburb', $suburbarray)
                ->whereIn('country', $countryarray)
                ->whereIn('state', $statearray)->get();

                //put this somewhere useful later remember usort(array,'cmp')

                $users = $users->toArray(); // Convert user collection to array

                 //static


                usort($users, array("App\Http\Controllers\SearchController", "cmp"));





                return Response::json( array(
                            'searcherror' => $users
                        ) );  
            }   

编辑:试过了,固定类路径得到了这个

为 foreach() 提供的参数无效

您的排序功能有问题

注意:用户位置以及经纬度可以通过用户对象中的方法访问

$user->getLoc() 所以基本上我们可以像这样访问它,例如 $user->getLoc()->经度

【问题讨论】:

    标签: php mysql laravel spatial


    【解决方案1】:

    您现在可以使用自定义比较器对用户数组进行排序,该比较器将使用排序后的位置数组在两个用户之间进行比较。

    代码示例-

    class SomeController
    {
        function someFunction()
        {
            $places = ...; // The places are already calculated by you
            $users = ...; // Users are also fetched in the code
    
            $users = $users->toArray(); // Convert user collection to array
    
            usort($users, function($user1, $user2) use($places)
            {
                foreach($places->toArray() as $place)
                {
                    if(($place->country == $user1->country) && ($place->suburb == $user1->suburb) && ($place->state == $user1->state))
                    {
                         return true;
                    } 
                    if(($place->country == $user2->country) && ($place->suburb == $user2->suburb) && ($place->state == $user2->state))
                    {
                         return false;
                    } 
                }
                return false;
            });
    
            // The array $users is now sorted based on user places
        }
    }
    

    您还可以使用哈希图类型的结构来优化地点搜索,这将加快您的代码复杂性。

    【讨论】:

    • 感谢您的帮助,非常感谢。我试过但是我遇到了这个:usort() 期望参数 1 是数组,给定对象
    • 好的,->get() 方法返回一个 Collection 对象,我们需要将其转换为数组,然后才能在 usort 中使用。我已经相应地更新了代码。看看
    • 我已将 toArray() 合并到 $users 对象中。没有骰子。请看我的编辑
    • 参考php usort文档secure.php.net/manual/en/…,如果你在类中使用它,那么你的比较器需要是一个静态方法,你需要传递className数组和比较器
    • 不确定您的意思。不会让我把函数变成静态的,也不知道把它放在哪里
    【解决方案2】:

    这是我的最终解决方案!知道了! 只需要修改 sql 查询并添加左连接:D

    哇哇哇!!!!!!

    //spatial queries
    
                    //$circle_radius = 3959; //miles
                    $circle_radius = 6371; //kms
                    $max_distance = request('distance');
                    $lat = Auth::user()->getLoc()->latitude;
                    $lng = Auth::user()->getLoc()->longitude;
    
                    //get all nearby places
                     $places = DB::select(
                                   'SELECT * FROM
                                        (SELECT users.id, users.country, users.suburb, users.state, places.latitude, places.longitude, (' . $circle_radius . ' * acos(cos(radians(' . $lat . ')) * cos(radians(latitude)) *
                                        cos(radians(longitude) - radians(' . $lng . ')) +
                                        sin(radians(' . $lat . ')) * sin(radians(latitude))))
                                        AS distance
                                        FROM users
                                        LEFT JOIN places ON users.suburb=places.suburb) AS distances
                                    WHERE distance < ' . $max_distance . '
                                    ORDER BY distance;
                                ');
    
    
                     /*
    
                    $result = User::contains('country', $places->country)
                    ->contains('state', $places->state)
                    ->contains('postcode', $places->postcode)
                    ->contains('suburb', $places->suburb)
                    ->get();
                    */
    
    
    
                    $places = (object)$places;
    
    
                    return Response::json( array(
                                'searcherror' => $places
                            ) );  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-22
      • 2018-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-22
      相关资源
      最近更新 更多