MongoDB LBS应用

前面简单的写下了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:”肯德基”}} )