1、用途介绍
因为项目需要,第一次接触mongodb的空间索引,之前没有了解过,就查询了一些资料,并将自己的学习经历记录下来,遗憾的是当初资料都没有记录下来资料出处,这里要向那些给我提供帮助的作者道个歉。我的项目是涉及到一个查询公司仓库附近的可用合作车辆,在大佬的推荐下,使用了空间索引,接下来说明具体思路。
2、建立思路
2.1、前提要求
首先保存数据的实体中需要有一个Double类型的一维数组,存放经纬度的信息。这时打开你的数据库管理工具,我用的Navicat,这时第一个重点来了:需要给已经生成的集合添加索引了,我之前创建的实体类是Location,一维数组的字段是loc;我们需要用到mongo的语法,
添加空间索引:db.Location.ensureIndex({"loc":"2d"})
成功后查询索引:db.Location.getIndexes()
就可以看到:
现在就完成一半了,并且空间索引是会一直存在的,不会出现你添加索引之前的数据能使用索引,之后添加的数据不能用的情况,所以添加一次即可。
如果添加错了,可用 db.Location.dropIndex(“loc_2d”) 命令来删除指定索引;
2.2、代码查询
我们公司用的是jdbc对数据库做操作,所以我对数据操作用的是MongoTemplate的模板类。代码如下
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import java.util.ArrayList;
import java.util.List;
/**
* 查询指定地点附近的可用车辆
* @param lng 经度
* @param lat 纬度
* @param maxDistance 圆形范围半径,单位KM
* @return 符合条件的结果集
*/
public List<Location> findNear(Double lng, Double lat, double maxDistance){
Point point = new Point(lng, lat); //lng是经度,lat是纬度
Query query = new Query();
//maxDistance必须是浮点型,整型的计算结果会为0
Criteria criteria = Criteria.where("loc").near(point).maxDistance(maxDistance / 111);
List<Location> list = mongoTemplate.find(query, Location.class);
if(list!=null && list.size()>0){
return list;
}else{
return new ArrayList<Location>();
}
}
这是通过圆心以指定半径来查找,还有另一种通过指定方形范围来查找,我也贴出来吧。代码如下
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
/**
* 按方形查找
* @param lowerLeft 对角线的点的经纬度
* @param upperRight 对角线的点的经纬度
* @return
*/
public List<Location> findBoxWithin(Point lowerLeft, Point upperRight) {
Query query = new Query(Criteria.where("loc").within(new Box(lowerLeft, upperRight)));
return mongoTemplate.find(query, Location.class);
}
如有需要可以自己cv修改。
2.3、Navicat方式查询
这种我没怎么用,因为毕竟在生产环境中还是得用代码,不过还是贴出来以备不时之需。
自动查询前100条数据。
db.runCommand({
"geoNear":"location", //指定要在那个数据集里查询
“near” : [0,0] //指点目标点的经纬度
})
3、总结
在工作中还发现一个问题,实体类中给成员变量添加@Id注解或者成员变量名是id都会使主键固定,也就是mongo不会自动给每条数据生产_id了,在新增数据时,如果id属性值相同就会自动覆盖之前的旧数据。
空间索引还是有很大的用处的,就像地图搜索附近的应用,感觉也是用到了这个,但是不确定是不是mongodb,因为mysql好像也有空间索引,但是还没具体了解过。以后遇到了再补充。