GeoJSON字段必须为Point类型且坐标顺序为[longitude, latitude],需建2dsphere索引,$near查询须用$geometry包裹并设$maxDistance(单位米),聚合中用$geoNear需置首阶段且显式设spherical:true。

GeoJSON字段必须用Point类型且坐标顺序为[longitude, latitude]
MongoDB只认标准GeoJSON格式,Point是唯一支持地理空间查询的几何类型(LineString、Polygon不能直接用于$near)。常见错误是把坐标写成[latitude, longitude]——这会导致查询结果完全错乱,但MongoDB不会报错,只会返回空或异常近邻。
正确结构示例:
{
"name": "咖啡馆A",
"location": {
"type": "Point",
"coordinates": [-73.9857, 40.7484] // 注意:经度在前,纬度在后
}
}
-
coordinates数组长度必须为2,且值在有效范围内(经度-180~180,纬度-90~90) - 字段名不强制叫
location,但后续索引和查询需保持一致 - 避免嵌套过深,如
{"geo": {"data": {"type":...}}}——会增加索引和查询复杂度
必须创建2dsphere索引,不能用2d
2d索引仅支持平面坐标(如笛卡尔坐标),对地球曲率无感知,10km以上距离误差极大;2dsphere才真正支持球面几何计算,是GeoJSON查询的硬性前提。
建索引命令:
db.places.createIndex({ "location": "2dsphere" })
- 索引字段路径必须与文档中GeoJSON对象路径完全一致(比如用
"address.geo"就索引address.geo) - 一个集合只能有一个
2dsphere索引,但可与其他字段组合(如{"location": "2dsphere", "status": 1}) - 索引创建后需用
db.places.getIndexes()确认状态,避免因拼写错误导致索引未生效
$near查询必须配合$geometry和$maxDistance
直接对Point字段用$near会失败,必须包裹在$geometry中声明GeoJSON结构。不设$maxDistance可能导致全量扫描,尤其在数据量大时响应极慢。
典型查询:
db.places.find({
"location": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [-73.9857, 40.7484]
},
"$maxDistance": 1000 // 单位:米
}
}
})
-
$maxDistance单位始终是**米**,不是千米或英里 - 若需分页,用
$limit+$skip效率低,建议改用$minDistance做游标分页 -
$near默认按距离升序,无法直接倒序;如需“最远的10个”,得先查再内存排序
聚合管道中$geoNear比$near更灵活但有约束
当需要同时返回距离、排序、过滤或关联其他字段时,$geoNear是唯一选择——但它必须是聚合管道的第一阶段,且集合必须有2dsphere索引。
示例(返回带距离字段的结果):
[
{
"$geoNear": {
"near": { "type": "Point", "coordinates": [-73.9857, 40.7484] },
"distanceField": "dist.calculated",
"maxDistance": 5000,
"spherical": true
}
}
]
-
distanceField指定新字段名存距离值,后续阶段可直接引用 -
spherical: true必须显式设置,否则默认按平面算(即使索引是2dsphere) - 不能在
$geoNear后接$text搜索——全文索引和地理索引无法共存于同一阶段
实际部署时最容易忽略的是坐标顺序和$maxDistance的单位。这两个点出错,查询看起来能跑通,但结果毫无业务意义。











