MongoDB地理位置功能总结
1. 术语
术语 | 术语解释 |
---|---|
Legacy Coordinates | 笛卡尔坐标系,即平面坐标系。 |
GeoJSON | GeoJSON是基于JavaScript 对象表示法的地理空间信息数据交换格式。GeoJSON对象可以表示几何、特征或者特征集合。GeoJSON支持下面几何类型:点、线、面、多点、多线、多面和几何集合。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。更多信息见 GeoJSON 。MongoDB中存储地理位置信息,建议采用GeoJSON格式存储。下文为该数据格式的示例。 |
距离单位 | 米(meter);平面单位(flat units):可以理解为经纬度的一度;弧度(radians):弧度乘以地球平均半径6359KM,近似表示地面距离 |
![image.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC9wbmcvMTczMjQyNS8xNTk4MDY2MjA4NjExLTBlNDFlMDE3LWU5NTAtNDE4YS1hZTM4LWYyMGUxMWFkOGIzYi5wbmc?x-oss-process=image/format,png#align=left&display=inline&height=498&margin=[object Object]&name=image.png&originHeight=586&originWidth=883&size=61453&status=done&style=shadow&width=750)
2. 索引类型
MongoDB支持两种索引:
索引类型 | 说明 |
---|---|
2dsphere | 球面索引,支持在类似地球的球体上计算几何图形的查询。 |
数据允许的情况下,均应改用该类索引。 | |
2d | 二维平面点的索引,用于计算平面距离。仅在存储的数据不能满足GeoJSON格式时,采用该索引。仅部分命令支持 2d 索引,只能在笛卡尔坐标对上创建。 |
创建命令如下
// 比如有places集合的数据如下
db.places.insert(
{
location : {
type: "Point", coordinates: [ -73.97, 40.77 ] },
name: "Central Park",
category : "Parks"
}
)
// 创建2dsphere索引
db.places.createIndex( {
location : "2dsphere"} )
// 创建2d索引
db.places.createIndex( {
"location.coordinates" : "2d"} )
另外地理位置索引支持与普通索引一起创建联合索引
// 组合索引:普通索引设置 1 正序, -1 倒序
db.places.createIndex( {
location : "2dsphere" , category : -1, name: 1 } )
// 或者,2dsphere不一定在最前面
db.places.createIndex( {
category : -1, location : "2dsphere" } )
3. 常用MongoDB地理位置方法
查询类型 | 几何类型 | 备注 |
---|---|---|
$near (GeoJSON点,2dsphere索引) |
球面 | 输入为GeoJSON时需要为2dsphere索引。结果已经排序,由近及远。MongoDB 4.0之前的版本不支持分片集群!!! |
$near (传统坐标,2d索引) |
平面 | 输入为普通坐标点时需要为2索引。结果已经排序,由近及远。MongoDB 4.0之前的版本不支持分片集群!!! |
$nearSphere (GeoJSON点,2dsphere索引) |
球面 | 结果已经排序,由近及远。MongoDB 4.0之前的版本不支持分片集群!!! |
$nearSphere (传统坐标,2d索引) |
球面 | 传统坐标会自动转化为GeoJSON点结果已经排序,由近及远。MongoDB 4.0之前的版本不支持分片集群!!! |
$geoWithin:{$geometry:...} |
球面 | |
$geoWithin:{$box:...} |
平面 | |
$geoWithin:{$polygon:...} |
平面 | |
$geoWithin:{$center:...} |
平面 | |
$geoWithin:{$centerSphere:...} |
球面 | |
$geoIntersects |
球面 |
4. 距离计算测试
- 下面通过一个测试库验证下上面方法,测试collection的数据结构为
mongoimport restaurants.json -c restaurants
imported 25359 documents
mongoimport restaurants.json -c restaurants2
imported 25359 documents
db.restaurants.findOne()
{
"_id" : ObjectId("55cba2476c522cafdb05731e"),
"location" : {
"coordinates" : [
-73.937699,
40.8185813
],
"type" : "Point"
},
"name" : "Makkah Pizza Restaurant"
}
- 创建索引
db.restaurants.createIndex({
"location": "2dsphere" })
db.restaurants.createIndex({
"location.coordinates": "2d" })
上面命令,分别创建了一个2dsphere索引和一个2d索引。
$near
/$nearSphere
传入传统坐标点,使用2d索引
注意距离的单位是弧度,弧度乘以地球半径可以得到距离千米数,比如平面500米范围,其实是直径1公里的圆,转换为弧度为1.0/6359.0
// 查询500米范围内的餐馆
// $near
db.restaurants.find({
"location.coordinates":{
$near: [ -73.93769, 40.8185 ],$maxDistance: 1.0/6359.0} } ).count()
// 输出为1
// $nearSphere
db.restaurants.find({
"location.coordinates":{
$nearSphere: [