前面简单的写下了Find方式基于索引的检索,见《MongoDB的GeoSpatial索引 》好久没把这个补充完整,刚写完这边整体的检索代码,趁热打铁,写完这篇。
Find查询,仅仅能根据2d坐标按距离排序的POI点,查询出列表以后还得自己计算距离,实际开发的同学肯定会思考这点,既然有了排序功能那么肯定有拿到距离的数据了。
参考这两个视频,蛮好的,英语比较不好,听了好多遍看着文档,弄明白了:
http://www.10gen.com/presentations/mongosf-2011/geospatial-indexing-mongodb
http://www.10gen.com/presentations/mongosf2011/wordsquared
GeoNear命令,是基于db的command,而不是基于collection的find,也就是需要通过runcommand执行,具体语法如下:
db.runCommand({ geoNear : “collectionName” , near : [120.123456,30.654321], num : 10 } )
解释下这个命令:就是查询geoNear的collection中,距离near指定点最近的10条记录,简单吧?结果如下:
{
"ns" :
"poi.collectionName"
,
"near" :
"1100110000001111110000001111110000001111110000001111"
,
"results" : [
{
"dis" :
0.29646421910687
,
"obj" : {
"_id" :
92
,
"y" : [
120.123456,
30.654321
],
"category" :
"Coffee"
}
},
{
"dis" :
1.21645345345
,
"obj" : {
"_id" :
54
,
"y" : [
120.123456,
30.654321
]
}
},
{
"dis" :
1.31645345345
,
"obj" : {
"_id" :
33
,
"y" : [
120.123456,
30.654321
]
}
}
],
"stats" : {
"time" :
0
,
"btreelocs" :
1
,
"btreelocs" :
1
,
"nscanned" :
3
,
"nscanned" :
3
,
"objectsLoaded" :
3
,
"objectsLoaded" :
3
,
"avgDistance" :
1.29646421910687
}
,
"ok" :
1
}
这个结果是根据距离排序有距离的记录,但是距离是经纬度的差值,MongoDB 1.8以后提供了Spherical Model,用distanceMultiplier指定地球半径来得到实际的公里或者米的距离,记得加上spherical:true,命令变为:
db.runCommand({ geoNear : “collectionName” , near : [120.123456,30.654321], distanceMultiplier: 6378137, num : 10, spherical:true } )
那么查出的结果中距离就是实际的米
【注】我开始用百度坐标,不准,因为国内的地图坐标系都是经过偏移过的,后来采用google map地图的坐标,算出来的距离和google
api中提供的距离结果只相差1~2米。
这个num参数是取得记录数目,适合做列表翻页用,但是地图上我们很难说只取多少个点,而是取多大屏幕范围,那么maxDistance参数正好适合,也就是多少范围的;我上面采用的地球半径是米,那么这里查询我统一采用米来计算,命令变为:
db.runCommand({ geoNear : “collectionName” , near : [120.123456,30.654321], distanceMultiplier: 6378137, maxDistance:2500/6378137 ,spherical:true} )
也就是查询2500米范围内的poi;
其他参数还有个Query,用于联合查询,如:
db.runCommand({ geoNear : “collectionName” , near : [120.123456,30.654321], distanceMultiplier: 6378137, num : 10, spherical:true , query:{Name:”肯德基”}} )