首页 / MongoDB 入门教程 / 地理空间索引

MongoDB 入门教程

地理空间索引

本教程共 50 篇 · 第 44 篇 · 更新于 2026-07-30 · 约 3 分钟阅读

MongoDBMongoDB 入门教程地理空间2dsphereGeoJSON附近查询

44. 地理空间索引

本节目标:会存 GeoJSON 坐标、建 2dsphere 索引,并用 $near、$geoWithin、$geoIntersects 做空间查询。

很多业务要回答「离我最近的店」「这个区域内的商品」。MongoDB 用地理空间索引(Geospatial Index)支持这类查询。我们的 products 正好带了 location 字段。

44.1 GeoJSON:坐标怎么存

MongoDB 推荐用 GeoJSON 对象存地理数据。它就是一个内嵌文档,含 typecoordinates 两个字段。

// products 里每个商品带一个 Point 位置
test> db.products.insertMany([
  { _id: 11, name: "西湖店键盘", price: 399, category: "外设",
    location: { type: "Point", coordinates: [120.15, 30.25] } },
  { _id: 12, name: "武林店鼠标", price: 89, category: "外设",
    location: { type: "Point", coordinates: [120.16, 30.27] } },
  { _id: 13, name: "滨江店耳机", price: 199, category: "外设",
    location: { type: "Point", coordinates: [120.21, 30.20] } }
])
Warning

GeoJSON 坐标顺序是「经度在前,纬度在后」[经度, 纬度]。写反了位置会跑到地球另一端,这个坑我见过不止一次。

常见 GeoJSON 类型有三种:

  • Point:点,比如一家门店。
  • LineString:线,比如一条配送路线。
  • Polygon:面,比如一个配送圈或行政区。

44.2 建 2dsphere 索引

球面计算要用 2dsphere 索引。它基于 WGS84 参考系,按地球曲面算距离。

// 给 location 建 2dsphere 索引
test> db.products.createIndex({ location: "2dsphere" })
Note

平面计算用老的 2d 索引;真实经纬度场景一律用 2dsphere,别用错。

44.3 $near:找离我最近的

$near 按距离从近到远返回,且必须配合地理空间索引。

// 以西湖坐标为圆心,找 5 公里内的商品
test> db.products.find({
  location: {
    $near: {
      $geometry: { type: "Point", coordinates: [120.15, 30.25] },
      $maxDistance: 5000
    }
  }
})

不写 $maxDistance 也会返回,只是不限最远距离。结果与距离从小到大排列。

44.4 $geoWithin:圈出一个范围

$geoWithin 选出落在某形状内的文档,不会排序。常用 $centerSphere 画一个圆(单位是弧度):

// 以指定点为中心、半径 10 公里(约 0.00157 弧度)的圆内商品
test> db.products.find({
  location: {
    $geoWithin: {
      $centerSphere: [ [120.15, 30.25], 10 / 6378.1 ]
    }
  }
})

也可以用 Polygon 圈一个任意多边形区域:

// 用多边形框选一片区域
test> db.products.find({
  location: {
    $geoWithin: {
      $geometry: {
        type: "Polygon",
        coordinates: [ [ [120.10, 30.20], [120.25, 30.20], [120.25, 30.30], [120.10, 30.30], [120.10, 30.20] ] ]
      }
    }
  }
})

44.5 $geoIntersects:判断相交

$geoIntersects 用来判断几何是否相交。比如一条配送路线(LineString)是否经过某个区域(Polygon)。

// 一条路线是否穿过上面的配送圈
test> db.routes.find({
  path: {
    $geoIntersects: {
      $geometry: {
        type: "Polygon",
        coordinates: [ [ [120.10, 30.20], [120.25, 30.20], [120.25, 30.30], [120.10, 30.30], [120.10, 30.20] ] ]
      }
    }
  }
})
Tip

记住三个算子的分工:$near 管「最近排序」,$geoWithin 管「圈内筛选」,$geoIntersects 管「是否相交」。

44.6 小结

地理数据用 GeoJSON 存(经度在前)。建 2dsphere 索引后,用 $near 查最近、$geoWithin 圈范围、$geoIntersects 判相交。Point、LineString、Polygon 三类形状覆盖绝大多数位置场景。