产品背景:需要根据客户端传过来的用户gps坐标查看附近1km是否有跑步路线。
技术背景:该项目使用的数据库是mongodb。
(内心背景:想顺便学习mongodb)
经查阅mongodb相关文档,发现Mongodb中的$nearSphere很适合这个场景,于是经技术评审后决定采用$nearSphere来做。
定义
-
$nearSphere
- 指定地理空间查询从最近到最远返回文档的点。 MongoDB 使用球面几何计算$nearSphere的距离。
$nearSphere需要地理空间索引:
-
2 dsphere定义为 GeoJSON 点的位置数据索引
-
2 d定义为 legacy 坐标对的位置数据的索引。要在GeoJSON 指出上使用2 d索引,请在 GeoJSON object 的
coordinates
字段上创建索引。
$nearSphere operator 可以指定以 GeoJSON point 或 legacy 坐标点。
要指定GeoJSON Point,请使用以下语法:
{
$nearSphere: {
$geometry: {
type : "Point",
coordinates : [ <longitude>, <latitude> ]
},
$minDistance: <distance in meters>,
$maxDistance: <distance in meters>
}
}
例子
使用 GeoJSON 指定中心点
考虑一个包含location
字段且具有2 dsphere索引的文档的集合places
。
然后,以下 example 返回其location
距指定点至少1000
米并且距离指定点最多5000
米,从最近到最远排序:
db.places.find(
{
location: {
$nearSphere: {
$geometry: {
type : "Point",
coordinates : [ -73.9667, 40.78 ]
},
$minDistance: 1000,
$maxDistance: 5000
}
}
}
)
使用
/**
* 指定一个点,返回该点附近的坐标点且是由近到远,$nearSphere 需要建立索引2dsphere 或者2d,并且支持GeoJSON和一般坐标对 注意:
* $nearSphere在分片的集群中无效,使用geoNear
*
* @param collection 集合名称
* @param locationField 坐标字段
* @param center 中心点坐标[经度,纬度]
* @param minDistance 最近距离
* @param maxDistance 最远距离
* @param query 查询条件
* @param fields 查询字段
* @param limit 返回记录限制数量
* @return 非NULL的list
*/
public List<DBObject> nearSphere(String collection, String locationField, Point center,
long minDistance, long maxDistance, DBObject query, DBObject fields, int limit) {
if (query == null) {
query = new BasicDBObject();
}
query.put(locationField,
new BasicDBObject("$nearSphere",
new BasicDBObject("$geometry",
new BasicDBObject("type", "Point").append("coordinates",
new double[]{center.getX(), center.getY()}))
.append("$minDistance", minDistance)
.append("$maxDistance", maxDistance)));
return mongoTemplate.getCollection(collection).find(query, fields).limit(limit).toArray();
}
注意事项
1、locationField指定字段必须是已经建立了索引的
(网图侵删),
如上面所示,添加2dsphere索引后的列才可以使用nearSphere查询。
2、nearSphere查询出来的结果是根据附近的坐标点由近到远排序的,这样就很方便了,不需要二次排序,我之前就是因为不知道这个特性浪费了一点时间去搞这个排序。