mongodb通过$geoNear进行坐标检索

最近的项目涉及带geo信息的多源数据融合,发现mongo3.x的geo检索跟2.x有点变化,在这里mark一下。

//1.建立geo索引
db.point.ensureIndex({"geo":"2d"});
//"geo"格式说明:
[
  116.279943 #lng经度
  40.049971, #lat纬度
]

//2.插入示例数据
db.point.insert({ "@id" : 1, "@geo" : [ 116.305297, 40.041993 ], "@bucket":["稻香村"], "@bucket_sign":["19d40bb2165c198560278e7bc3b2c5e5"] ,"name":"稻香村上地店"})
db.point.insert({ "@id" : 2, "@geo" : [ 116.305306, 40.041995 ], "@bucket":["稻香村"], "@bucket_sign":["19d40bb2165c198560278e7bc3b2c5e5"] ,"name":"稻香村西二旗店" })
db.point.insert({ "@id" : 3, "@geo" : [ 116.305309, 40.041993 ], "@bucket":["海底捞"], "@bucket_sign":["f6c832afc1c578ee731273c14a0245b4"] ,"name":"海底捞西二旗店" })
db.point.insert({ "@id" : 4, "@geo" : [ 116.279943,40.049971 ], "@bucket":["海底捞"], "@bucket_sign":["f6c832afc1c578ee731273c14a0245b4"] ,"name":"海底捞上地店" })
db.point.insert({ "@id" : 5, "@geo" : [ 116.225901,39.773136 ], "@bucket":["海底捞"], "@bucket_sign":["f6c832afc1c578ee731273c14a0245b4"] ,"name":"海底捞房山长阳店" })


//3.查询附近1公里的点示例:

1)find标准查询(仅mongodb2.x版本支持,不能返回距离)
db.point.find({"geo ":{ $near : [116.279943,40.049971] , $maxDistance : 1/111.12},"@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4"}) 返回格式: { "_id" : ObjectId("59f8418c278994d6d2e77c9a"), "@id" : 4, "@geo" : [ 116.279943, 40.049971 ], "@bucket" : [ "海底捞" ], "@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4" ], "name" : "海底捞上地店", "dist" : { "calculated" : 0, "location" : [ 116.279943, 40.049971 ] } } { "_id" : ObjectId("59f8418c278994d6d2e77c99"), "@id" : 3, "@geo" : [ 116.305309, 40.041993 ], "@bucket" : [ "海底捞" ], "@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4" ], "name" : "海底捞西二旗店", "dist" : { "calculated" : 2.33435844594686, "location" : [ 116.305309, 40.041993 ] } } { "_id" : ObjectId("59f8418c278994d6d2e77c9b"), "@id" : 5, "@geo" : [ 116.225901, 39.773136 ], "@bucket" : [ "海底捞" ], "@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4" ], "name" : "海底捞房山长阳店", "dist" : { "calculated" : 31.12581912580905, "location" : [ 116.225901, 39.773136 ] } } 2)aggregate聚合查询 返回格式与find相同。参数中$maxDistance为经纬弧度(1° latitude = 111.12 kilometers)即 1/111.12,表>示查找附近一公里。 db.point.aggregate([{$geoNear:{near:[116.279943,40.049971],distanceField: "dist.calculated",maxDistance: 100/111.12,query:{"@bucket_sign":"f6c832afc1c578ee731273c14a0245b4"},includeLocs: "dist.location",uniqueDocs: true,num: 5,spherical:true,"distanceMultiplier": 6371}}]) 返回同1)find格式


3)runCommand命令方式 
db.runCommand({geoNear:"point",near:[116.305207,40.042053 ], maxDistance : 1/111.12,query: { "@bucket":"海底捞" }}) 

返回格式:
 { "ns" : "point", "near" : "", "results" : [ { "dis" : 0.0001138771267725113, "obj" : { "_id" : ObjectId("59eeeed3b5fbf3fa598cd4b0"), "@id" : 4, "@geo" : [ 40.041995, 116.305305 ], "@bucket" : [ "海底捞" ], "@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4" ], "name" : "海底捞西北旺店" } }, { "dis" : 0.00011833849754085601, "obj" : { "_id" : ObjectId("59eeeed3b5fbf3fa598cd4af"), "@id" : 3, "@geo" : [ 40.041993, 116.305309 ], "@bucket" : [ "海底捞" ], "@bucket_sign" : [ "f6c832afc1c578ee731273c14a0245b4" ], "name" : "海底捞西二旗店" } } ], "stats" : { "time" : 2, "btreelocs" : 0, "nscanned" : 19, "objectsLoaded" : 10, "avgDistance" : 0.00011610781215668365, "maxDistance" : 0.00011833849754085601, "shards" : [ "ucp_shard_14", "ucp_shard_3", "ucp_shard_8" ] }, "ok" : 1 } 

注1:mongodb3.x版本的两种geoNear查询方式都支持返回距离并按距离正序排序。

注2:使用geoNear获得的结果里dis的单位,有两种情况:

1)spherical设为false(默认),dis的单位与坐标的单位保持一致
如果保存的是longitude/latitude,则dis的单位就是经度(或者纬度,单位是一致的)
如果保存的是meter,则dis的单位就是meter

2)spherical设为true,dis的单位是弧度

想要换算成公里(km)的话,
要么在程序里做,要么使用distanceMultiplier参数来定义转换方式:

对应于1)
如果要保存的坐标是经纬度,要计算的是公里,可设置 distanceMultiplier: 111
如果要计算英里,可将111换成69

对应于2)
如果要计算公里,可设置 distanceMultiplier: 6371
如果要计算英里,则需要把6371换成3959

 

yan 17.10.24

参考:

http://www.cnblogs.com/shanyou/p/3494854.html

http://www.dewen.net.cn/q/7412

欢迎关注下方“非著名资深码农“公众号进行交流~

发表评论

邮箱地址不会被公开。