【发布时间】:2016-12-21 11:59:42
【问题描述】:
我在 SilverStripe 3.4.0 中每个 mysql 过滤位置 Y 周围半径 X 内的位置。
到目前为止,我已经实现了一个原始查询来获取圆圈中的 ID,而不是使用它们来过滤每个 SilverStripe ORM,因为我必须根据多个条件进行过滤,而地理过滤器只是其中之一。
另请参阅 Google 的“商店定位器”示例: https://developers.google.com/maps/articles/phpsqlsearch_v3
$searchDistance = '...';
$searchLat = '...';
$searchLng = '...';
$geolimitedIDs = DB::query('SELECT id, (6371 * acos(cos(radians('.$searchLat.')) * cos(radians(Latitude)) * cos( radians(Longitude) - radians('.$searchLng.')) + sin(radians('.$searchLat.')) * sin(radians(Latitude))))
AS distance
FROM "DataObject"
HAVING distance < ' . $searchDistance . '
ORDER BY distance')->column();
if($geolimitedIDs) {
$DataObjects = $DataObjects->filter(array(
'ID' => $geolimitedIDs
));
}
在 _config 中,我创建了 DataObject-Tabel MyISAM
DataObject:
create_table_options:
MySQLDatabase:
'ENGINE=MyISAM'
这会提供所需的结果,但需要额外的查询。 是否可以将地理过滤器直接添加到 ORM 中的查询中?
【问题讨论】:
-
直接向 ORM 添加过滤器是什么意思?
-
@Shadow - SilverStripe 进行延迟加载。这意味着我们可以修改查询 $DataObjects。我的意思是像 $DataObjects->where('...')
-
由于您的查询只有一个having子句,我会使用dataobject类的
having()方法。但是,您可以轻松地将filter()方法中的任何内容包含在查询的 where 子句中。将此条件添加到原始查询中可能更容易,而不是尝试找出如何以 SilverStripe 的方式重写原始查询。 -
我没有说你会删除一个查询,但它会以最优化的方式做到这一点:直接在 mysql 上,因为这就是数据的来源,而不需要在 php 上进行额外的步骤。
-
附注:您的查询和下面的所有答案(此时)计算每一行的“精确”距离(可能不如它可能的精确,但仍然如此)。虽然当有 1000 行时,单行不需要太多时间,但处理查询需要时间。进行边界框搜索(位置在适合您距离的区域的 NE、SE、SW、NW 坐标内)要快得多,然后如果需要精确的距离,则在 PHP 中过滤这个(小得多)集。
标签: mysql orm geolocation silverstripe