必须使用标准GeoJSON格式{type:"Point",coordinates:[lng,lat]},经度在前纬度在后;建2dsphere索引前需清理非法数据,推荐加sparse:true;聚合用$geoNear获取真实距离(单位米),spherical:true不可省略。

必须用标准 GeoJSON 格式存,不能用 {lat: x, lng: y} 或 {latitude: x, longitude: y} 这类自定义结构。
字段结构必须是 {type: "Point", coordinates: [lng, lat]}
这是 MongoDB 2dsphere 索引唯一认的格式。常见错误包括:
- 把
coordinates写成[lat, lng](顺序颠倒)——会导致索引创建失败或查询无结果 - 用
location: {lat: 40.7128, lng: -74.0060}——createIndex({location: "2dsphere"})直接报错can't parse geometry - 字段名用
geo、position等不统一名称,后续所有查询和索引都得跟着改,容易漏
正确示例:
{
"name": "Starbucks",
"location": {
"type": "Point",
"coordinates": [-74.0060, 40.7128]
}
}
注意:coordinates 是数组,不是对象;经度在前、纬度在后;值必须在合法范围内(经度 [-180, 180],纬度 [-90, 90])。
建索引前务必清理或跳过非法数据
db.collection.createIndex({location: "2dsphere"}) 会全量扫描并校验每条文档的 location 字段。只要有一条是 null、空对象、坐标越界或缺少 type 字段,就会中断并报错。
- 先检查异常数据:
db.places.find({ "location.type": { $exists: false } }).count() - 若存在空值或脏数据,加
sparse: true跳过:db.places.createIndex({location: "2dsphere"}, {sparse: true}) - 生产环境建议预处理:用
$set+$cond统一转换前端传来的{latitude, longitude}结构
别混用 2d 和 2dsphere 索引
一个集合只能有一个地理空间索引。选错类型会导致距离计算失真:
-
2d索引只支持平面欧氏距离,适合小范围(比如室内定位),单位是“度”,$maxDistance含义模糊,不推荐用于真实 LBS 场景 -
2dsphere基于 WGS84 和球面模型(Haversine),$maxDistance单位是米,结果符合真实地理距离 - 如果已有旧数据用数组存
[lng, lat],仍可建2dsphere索引(MongoDB 支持),但不能混用{x: lng, y: lat}这种对象写法
聚合管道中用 $geoNear 获取距离字段
单纯用 $near 只能排序,不返回实际距离。需要显式距离值时,必须走聚合阶段:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [-74.0060, 40.7128] },
distanceField: "distance",
spherical: true,
maxDistance: 5000,
limit: 20
}
}
])
distanceField 生成的字段单位是米;spherical: true 不可省略(即使建的是 2dsphere 索引);该阶段必须放在 pipeline 第一位。
最易被忽略的一点:前端 Geolocation API 返回的是 {latitude, longitude},后端入库前不转成 [longitude, latitude] 数组,就必然踩坑。这个转换动作不能依赖客户端或中间件“大概率正确”,必须在插入前由服务端强制 Normalize。











