【问题标题】:How to get nearby users and distances?如何获取附近的用户和距离?
【发布时间】:2018-09-05 12:17:47
【问题描述】:

首先我想向您展示当前的数据库结构。有两个表:

用户

  • 身份证
  • 姓名
  • location_id

位置

  • 身份证
  • 城市
  • 纬度
  • lng

现在我想实现一个获取附近用户及其距离的 API。喜欢附近的用户:

{{name:user1,distance:5km},(name:user2,distance:7 km)}

【问题讨论】:

  • 您可以在数据库中实现存储过程来计算距离,然后选择有条件和排序的记录,比如最近的不超过5km。如果你使用 PostgreSQL - 看这个postgis.net
  • 同意@ineersa,你当然可以在 Transact SQL 中做到这一点。现在真正的问题是您拥有的用户数量和频率,因为这可能需要一些时间来计算。根据具体情况,您可能希望实现一个表来存储此信息。

标签: laravel geolocation


【解决方案1】:

你可以这样试试

用户模型

public function location(){
    return $this->belongsTo('App\Location');
}

在 Location 模型中创建一个函数名称rsine,然后创建一个以scopeIsWithinMaxDistance 命名的本地作用域,如下所示

位置模型

/**
 * Scope for adding distance filter
 */
public function scopeIsWithinMaxDistance($query, $rsine, $radius = 5)
{
    return $query->selectRaw("*, {$rsine} AS distance")
                 ->whereRaw("{$rsine} < ?", [$radius])
                 ->orderBy('distance');
}

/**
 * Sql command for finding distance between 2 coordinates
 */
public static function rsine($coordinates)
{
    return '(6371 * acos(cos(radians(' . $coordinates['latitude'] . ')) 
    * cos(radians(`lat`)) 
    * cos(radians(`lng`) 
    - radians(' . $coordinates['longitude'] . ')) 
    + sin(radians(' . $coordinates['latitude'] . ')) 
    * sin(radians(`lat`))))';
}

public static function convertKMToMiles($dist)
{
    return $dist * 1.609344;
}

现在在控制器中调用它

$coordinates = ['latitude' => '28.392200', 'longitude' => '77.320801'];

$rsine = Location::rsine($coordinates);

$radius = Location::convertKMToMiles(5); //convert KM to miles

$users = User::with(['location' => function ($query) use ($rsine) {
               $query->selectRaw("*, {$rsine} AS distance");
         }])->whereHas('location', function ($query) use ($radius, $rsine) {
               $query->isWithinMaxDistance($rsine, $radius);
         })->get();

现在你可以这样打印了

foreach($users as $user){
   $user->name;
   $user->location->city;
   $user->location->distance;
}

【讨论】:

  • SQLSTATE[42000]:语法错误或访问冲突:1064 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册以获取正确的语法以使用..........
  • 您需要将radians(latitude) 更改为radians(lat)radians(longitude) 更改为radians(lng) @987654 方法中的@9876543在您的位置表中有latlng 字段。更新答案检查一下
  • 我也试过下面的代码: public static function rsine($coordinates) { return Location::select('id', DB::raw(' 6371 * acos( cos( radians(' . $坐标['纬度'] . ') ) * cos( 弧度( lat ) ) * cos( 弧度( lng ) - 弧度(' . $coordinates['longitude'] . ') ) + sin( 弧度(' . $coordinates ['纬度'] . ') ) * sin( 弧度( lat ) ) ) 作为距离'))->get(); }
  • SQLSTATE[HY093]:无效参数号:混合命名和位置参数(SQL:选择*,*,[{\“距离\”:10723.218919804329},{\“距离\”:1285.513973341391} ,{\"distance\":1284.2498526350137}] AS 距离locations 其中users.location_id = locations.id 和 [{\"distance\":10723.218919804329},{\"distance\ ":1285.513973341391},{\"distance\":1284.2498526350137}] > 8.04672 order by distanceasc)",
  • 使用与我的答案相同的方法不要尝试将return Location::select 放入rsine 方法中,并将` 放入弧度(lat)然后尝试。这是一个工作代码,我在项目中使用过它
猜你喜欢
  • 2016-11-17
  • 2014-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2020-10-02
  • 1970-01-01
相关资源
最近更新 更多