MongoDB唯一支持球面计算的地理数据格式是GeoJSON,必须严格遵循{type:"Point",coordinates:[经度,纬度]}等规范,经度在前、纬度在后,且需创建2dsphere索引。

用 GeoJSON 格式存储点、线、面等地理数据
MongoDB 官方推荐且唯一支持球面计算(如真实地球距离)的结构是 GeoJSON。它不是可选项,而是 2dsphere 索引和 $nearSphere、$geoWithin 等操作符正常工作的前提。
必须严格遵循格式:{ type: "Point", coordinates: [longitude, latitude] } —— 注意顺序是经度在前、纬度在后,不是 [latitude, longitude]。写反会导致查询结果完全错误,且 MongoDB 不报错,只返回空或错乱数据。
- 点数据示例:
{"location": {"type": "Point", "coordinates": [116.404, 39.915]}} - 多边形需闭合:首尾坐标相同,且至少有 4 个点(构成封闭环)
- 字段名(如
location)可自定义,但索引必须建在这个字段上:db.collection.createIndex({"location": "2dsphere"}) - 避免混用:不要在一个字段里既存
Point又存Polygon;类型不一致会触发GeometryParseError
别用传统坐标对,除非你明确要平面计算
旧式数组 [lng, lat] 或嵌入文档 {lng: ..., lat: ...} 只能配合 2d 索引,它把地球当平面算距离 —— 在城市级短距(
更麻烦的是:2d 索引不支持 $geoWithin、$geoIntersects,也不支持 GeoJSON 多边形查询。一旦业务需要“查某行政区内的所有门店”,你就只能重改数据结构。
- 如果已有
[lng, lat]数组,转成 GeoJSON 只需一层包装:{"type": "Point", "coordinates": oldArray} -
2d索引已弃用警告:MongoDB 6.0+ 对2d的支持逐步收紧,新项目一律用2dsphere+GeoJSON - 坐标范围必须合法:经度 ∈ [-180, 180],纬度 ∈ [-90, 90];超出会直接插入失败或查询静默跳过
地理空间字段该不该嵌套?
可以嵌套,但索引路径必须精确到最深层字段。例如数据是 {"address": {"geo": {"type": "Point", "coordinates": [...]}}},那索引就得建在 "address.geo" 上,而不是 "address" 或 "geo"。
常见错误是字段层级写错,导致 createIndex 成功但查询无效果 —— MongoDB 不提示“索引未命中”,只返回空结果。
- 建议扁平化:直接用
{"loc": {...}},减少路径出错概率 - 若必须嵌套(如多地址场景),确保应用层写入时始终保证嵌套结构一致,否则部分文档因缺失
address.geo字段而无法被地理查询覆盖 - 聚合阶段(如
$geonear)中引用字段也必须用完整路径:near: "$address.geo"
复合索引里地理空间字段的位置很关键
2dsphere 字段在复合索引中必须放在**最后**。MongoDB 规定:地理空间索引字段不能出现在复合索引的中间或开头(除了唯一索引的 _id 后)。
比如想按“城市 + 距离”查,正确写法是:db.places.createIndex({"city": 1, "loc": "2dsphere"});如果写成 {"loc": "2dsphere", "city": 1},命令会执行成功,但 $near 查询将忽略该索引,退化为全表扫描。
- 验证方式:用
explain()查看查询计划,确认winningPlan中用了IXSCAN且indexName是你建的那个 - 复合索引不能含数组字段(如
tags: ["a","b"]),否则2dsphere部分失效 - 如果已有非地理字段的复合索引,新增地理查询需求时,不要试图复用;必须新建一个以地理字段结尾的索引
$nearSphere 和 $geoWithin 查询,并检查 explain() 输出。


















