}
}
> db.mapinfo.find({loc : {$near : [72,82]},"category" :
"coffee"})
{ "_id" : ObjectId("4d242dce3238ba30f9ca05ac"), "category" :
"coffee", "name" : "hangzhou coffee bar", "loc" : [ 71, 81 ] }
{ "_id" : ObjectId("4d242d8b3238ba30f9ca05a9"), "category" :
"coffee", "name" : "digoal coffee bar", "loc" : [ 70, 80 ] }
# 换一个经纬度后结果相反.
> db.mapinfo.find({loc : {$near : [69,69]},"category" :
"coffee"})
{ "_id" : ObjectId("4d242d8b3238ba30f9ca05a9"), "category" :
"coffee", "name" : "digoal coffee bar", "loc" : [ 70, 80 ] }
{ "_id" : ObjectId("4d242dce3238ba30f9ca05ac"), "category" :
"coffee", "name" : "hangzhou coffee bar", "loc" : [ 71, 81 ] }
# 2d默认取值范围[-179,-179]到[180,180] 包含这两个点,超出范围将报错
> db.mapinfo.insert({"category" : "bank","name" : "china people
bank","loc" : [181,181]})
point not in range
> db.mapinfo.insert({"category" : "bank","name" : "china people
bank","loc" : [-179,-180]})
in > 0
# 如果已经存在超过范围的值,建2D索引将报错
> db.mapinfo.insert({"category" : "bank","name" : "china people
bank","loc" : [-180,-180]})
> db.mapinfo.ensureIndex({"loc" :
"2d"})
in > 0
# 在建2d索引的时候可以指定取值范围
# 如,以上包含了[-180,-180]这个点之后,建2d索引将报错,使用以下解决.或者把这条记录先处理掉.
# 在限制条件下,min不包含,max包含,从下面建索引的语句中可以看出.
> db.mapinfo.ensureIndex({"loc" : "2d"},{min:-181,max:180})
> 成功
# 注意官方文档上说you can only have 1 geo2d index per collection right
now,不过测试可以建多个,如下
>
db.mapinfo.drop()
true
> db.mapinfo.insert({"category" : "bank","name" : "china people
bank","loc" : [71,81],"HQ_loc" : [91,101]})
> db.mapinfo.ensureIndex({"loc" : "2d"},{"background" :
"true"})
> db.mapinfo.ensureIndex({"HQ_loc" : "2d"},{"background" :
"true"})
> db.mapinfo.getIndexes()
[
{
"name" : "_id_",
"ns" : "test.mapinfo",
"key" : {
"_id" : 1
}
},
{
"_id" : ObjectId("4d2439803238ba30f9ca05cd"),
"ns" : "test.mapinfo",
"key" : {
"loc" : "2d"
},
"name" : "loc_",
"background" : "true"
},
{
"_id" : ObjectId("4d2439863238ba30f9ca05ce"),
"ns" : "test.mapinfo",
"key" : {
"HQ_loc" : "2d"
},
"name" : "HQ_loc_",
"background" : "true"
}
]
> db.mapinfo.find({"loc" : {"$near" :
[20,21]}})
{ "_id" : ObjectId("4d2439643238ba30f9ca05cc"), "category" :
"bank", "name" : "china people bank", "loc" : [ 71, 81 ], "HQ_loc"
: [ 91, 101 ] }
> db.mapinfo.find({"HQ_loc" : {"$near" : [20,21]}})
{ "_id" : ObjectId("4d2439643238ba30f9ca05cc"), "category" :
"bank", "name" : "china people bank", "loc" : [ 71, 81 ], "HQ_loc"
: [ 91, 101 ] }
# 使用范例2:
# 测试数据
> db.mapinfo.find()
{ "_id" : ObjectId("4d2439643238ba30f9ca05cc"), "category" :
"bank", "name" : "china people bank", "loc" : [ 71, 81 ], "HQ_loc"
: [ 91, 101 ] }
{ "_id" : ObjectId("4d243a743238ba30f9ca05cf"), "category" :
"coffee", "name" : "digoal coffee bar", "loc" : [ 100, 81 ],
"HQ_loc" : [ 100, 101 ] }
{ "_id" : ObjectId("4d243a8b3238ba30f9ca05d0"), "category" : "tea",
"name" : "digoal tea bar", "loc" : [ 110, 81 ], "HQ_loc" : [ 110,
101 ] }
{ "_id" : ObjectId("4d243ab23238ba30f9ca05d1"), "category" :
"shop", "name" : "digoal supermarket", "loc" : [ 120, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aba3238ba30f9ca05d2"), "category" :
"shop", "name" : "digoal supermarket1", "loc" : [ 121, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243abe3238ba30f9ca05d3"), "category" :
"shop", "name" : "digoal supermarket2", "loc" : [ 122, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243ac33238ba30f9ca05d4"), "category" :
"shop", "name" : "digoal supermarket3", "loc" : [ 123, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243ac83238ba30f9ca05d5"), "category" :
"shop", "name" : "digoal supermarket4", "loc" : [ 124, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243ace3238ba30f9ca05d6"), "category" :
"shop", "name" : "digoal supermarket5", "loc" : [ 125, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243ad63238ba30f9ca05d7"), "category" :
"shop", "name" : "digoal supermarket6", "loc" : [ 126, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aee3238ba30f9ca05d8"), "category" :
"shop", "name" : "digoal supermarket7", "loc" : [ 26, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af43238ba30f9ca05d9"), "category" :
"shop", "name" : "digoal supermarket8", "loc" : [ 27, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af93238ba30f9ca05da"), "category" :
"shop", "name" : "digoal supermarket9", "loc" : [ 29, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aff3238ba30f9ca05db"), "category" :
"shop", "name" : "digoal supermarket10", "loc" : [ 30, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243b063238ba30f9ca05dc"), "category" :
"shop", "name" : "digoal supermarket11", "loc" : [ 31, 81 ],
"HQ_loc" : [ 120, 101 ] }
# 索引
> db.mapinfo.getIndexes()
[
{
"name" : "_id_",
"ns" : "test.mapinfo",
"key" : {
"_id" : 1
}
},
{
"_id" : ObjectId("4d2439803238ba30f9ca05cd"),
"ns" : "test.mapinfo",
"key" : {
"loc" : "2d"
},
"name" : "loc_",
"background" : "true"
},
{
"_id" : ObjectId("4d2439863238ba30f9ca05ce"),
"ns" : "test.mapinfo",
"key" : {
"HQ_loc" : "2d"
},
"name" : "HQ_loc_",
"background" : "true"
}
]
# 查询离[50,50]最近的5家商店
> db.mapinfo.find({"loc" : {"$near" : [50,50]},"category" :
"shop"}).limit(5)
{ "_id" : ObjectId("4d243b063238ba30f9ca05dc"), "category" :
"shop", "name" : "digoal supermarket11", "loc" : [ 31, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aff3238ba30f9ca05db"), "category" :
"shop", "name" : "digoal supermarket10", "loc" : [ 30, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af93238ba30f9ca05da"), "category" :
"shop", "name" : "digoal supermarket9", "loc" : [ 29, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af43238ba30f9ca05d9"), "category" :
"shop", "name" : "digoal supermarket8", "loc" : [ 27, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aee3238ba30f9ca05d8"), "category" :
"shop", "name" : "digoal supermarket7", "loc" : [ 26, 81 ],
"HQ_loc" : [ 120, 101 ] }
# 找出限制离[50,50]在37 的商店,使用maxDistance
> db.mapinfo.find({"loc" : {"$near" : [50,50], "$maxDistance" :
37},"category" : "shop"})
{ "_id" : ObjectId("4d243b063238ba30f9ca05dc"), "category" :
"shop", "name" : "digoal supermarket11", "loc" : [ 31, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aff3238ba30f9ca05db"), "category" :
"shop", "name" : "digoal supermarket10", "loc" : [ 30, 81 ],
"HQ_loc" : [ 120, 101 ] }
# 复合索引
> db.mapinfo.ensureIndex({"loc" : "2d","category" :
1})
> db.mapinfo.getIndexes()
[
{
"name" : "_id_",
"ns" : "test.mapinfo",
"key" : {
"_id" : 1
}
},
{
"_id" : ObjectId("4d2439803238ba30f9ca05cd"),
"ns" : "test.mapinfo",
"key" : {
"loc" : "2d"
},
"name" : "loc_",
"background" : "true"
},
{
"_id" : ObjectId("4d2439863238ba30f9ca05ce"),
"ns" : "test.mapinfo",
"key" : {
"HQ_loc" : "2d"
},
"name" : "HQ_loc_",
"background" : "true"
},
{
"_id" : ObjectId("4d243ce13238ba30f9ca05dd"),
"ns" : "test.mapinfo",
"key" : {
"loc" : "2d",
"category" : 1
},
"name" : "loc__category_1"
}
]
3. 范例 3
# 除了使用find来搜索以外,还可以使用runCommand
> db.runCommand({"geoNear" : "mapinfo","near" : [50,50],"num" :
10})
{ "errmsg" : "more than 1 geo indexes :(", "ok" : 0 }
# 这里报错,原因是mapinfo超过一个2d索引,但是使用find来查询不会报错,
# 只保留一个“2d"索引后,使用runCommand正常
> db.mapinfo.dropIndex({"loc" : "2d","category" : 1})
{ "nIndexesWas" : 4, "ok" : 1 }
> db.runCommand({"geoNear" : "mapinfo","near" : [50,50],"num" :
10})
{ "errmsg" : "more than 1 geo indexes :(", "ok" : 0 }
> db.mapinfo.dropIndex({"HQ_loc" :
"2d"})
{ "nIndexesWas" : 3, "ok" : 1 }
# "num" 限制返回的记录数
# 使用runCommand和geoNear的好处是可以返回距离.本例"dis" : 36.3593194466869,
> db.runCommand({"geoNear" : "mapinfo","near" : [50,50],"num" :
1})
{
"ns" :
"test.mapinfo",
"near" :
"1100110000001111110000001111110000001111110000001111",
"results" : [
{
"dis" : 36.3593194466869,
"obj" : {
"_id" : ObjectId("4d243b063238ba30f9ca05dc"),
"category" : "shop",
"name" : "digoal supermarket11",
"loc" : [
31,
81
],
"HQ_loc" : [
120,
101
]
}
}
],
"stats" : {
"time" : 0,
"btreelocs" : 6,
"nscanned" : 7,
"objectsLoaded" : 3,
"avgDistance" : 36.3593194466869,
"maxDistance" : 36.3593194466869
},
"ok" : 1
}
# 使用runCommand同样也可以使用普通的FIND的限制条件,如下放在query : { "category" :
"coffee" }
> db.runCommand({"geoNear" : "mapinfo","near" : [50,50],"num" :
1,query : { "category" : "coffee" }})
{
"ns" :
"test.mapinfo",
"near" :
"1100110000001111110000001111110000001111110000001111",
"results" : [
{
"dis" : 58.830266786369556,
"obj" : {
"_id" : ObjectId("4d243a743238ba30f9ca05cf"),
"category" : "coffee",
"name" : "digoal coffee bar",
"loc" : [
100,
81
],
"HQ_loc" : [
100,
101
]
}
}
],
"stats" : {
"time" : 0,
"btreelocs" : 15,
"nscanned" : 15,
"objectsLoaded" : 7,
"avgDistance" : 58.830266786369556,
"maxDistance" : 58.830266786369556
},
"ok" : 1
}
4. 范例4
# 空间索引还支持范围搜索,目前支持圆和矩阵的范围
# 使用box
> box =
[[19,19],[90,90]]
[ [ 19, 19 ], [ 90, 90 ] ]
> db.mapinfo.find({"loc" : {"$within" : {"$box" : box}}})
{ "_id" : ObjectId("4d2439643238ba30f9ca05cc"), "category" :
"bank", "name" : "china people bank", "loc" : [ 71, 81 ], "HQ_loc"
: [ 91, 101 ] }
{ "_id" : ObjectId("4d243b063238ba30f9ca05dc"), "category" :
"shop", "name" : "digoal supermarket11", "loc" : [ 31, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aff3238ba30f9ca05db"), "category" :
"shop", "name" : "digoal supermarket10", "loc" : [ 30, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af93238ba30f9ca05da"), "category" :
"shop", "name" : "digoal supermarket9", "loc" : [ 29, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af43238ba30f9ca05d9"), "category" :
"shop", "name" : "digoal supermarket8", "loc" : [ 27, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aee3238ba30f9ca05d8"), "category" :
"shop", "name" : "digoal supermarket7", "loc" : [ 26, 81 ],
"HQ_loc" : [ 120, 101 ] }
# 使用center point and radius
> center = [29,81]
[ 29, 81 ]
> radius = 10
10
> db.mapinfo.find({"loc" : {"$within" : {"$center" :
[center,radius]}}})
{ "_id" : ObjectId("4d243af93238ba30f9ca05da"), "category" :
"shop", "name" : "digoal supermarket9", "loc" : [ 29, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243af43238ba30f9ca05d9"), "category" :
"shop", "name" : "digoal supermarket8", "loc" : [ 27, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aff3238ba30f9ca05db"), "category" :
"shop", "name" : "digoal supermarket10", "loc" : [ 30, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243b063238ba30f9ca05dc"), "category" :
"shop", "name" : "digoal supermarket11", "loc" : [ 31, 81 ],
"HQ_loc" : [ 120, 101 ] }
{ "_id" : ObjectId("4d243aee3238ba30f9ca05d8"), "category" :
"shop", "name" : "digoal supermarket7", "loc" : [ 26, 81 ],
"HQ_loc" : [ 120, 101 ] }
注意事项:
1. mongoDB处理的是平面距离,但是实际生活中如果涉及到大范围的距离搜索,可能会有偏差,因为地球是球型的。The current
implementation assumes an idealized model of a flat earth, meaning
that an arcdegree of latitude (y) and longitude (x) represent the
same distance everywhere. This is only true at the equator where
they are both about equal to 69 miles or 111km. However, at the
10gen offices at { x : -74 , y : 40.74 } one arcdegree of
longitude is about 52 miles or 83 km (latitude is unchanged). This
means that something 1 mile to the north would seem closer than
something 1 mile to the east.
2. 2d索引目前还不支持sharding,In the meantime sharded clusters can use
geospatial indexes for unsharded collections within the
cluster.
3. New Spherical Model,1.7.0以后将引入新的空间模型.
其他:
The current implementation encodes geographic hash codes atop
standard MongoDB b-trees. Results of $near queries are exact. The
problem with geohashing is that prefix lookups don't give you exact
results, especially around bit flip areas. MongoDB solves this by
doing a grid by grid search after the initial prefix scan. This
guarantees performance remains very high while providing correct
results