必须用GeoJSON Point存坐标({"type":"Point","coordinates":[lng,lat]}),建2dsphere索引,查询用$near配合$geometry和$minDistance/$maxDistance(单位米)。

Go 操作 MongoDB 地理位置查询,核心就三件事:数据存对、索引建对、查法写对。错一个,$near 返回结果乱序、距离不准、甚至直接报错。
location 字段必须是标准 GeoJSON Point
MongoDB 的 2dsphere 索引只认严格符合 GeoJSON 规范的结构,不是随便塞个数组或对象就行。
- ✅ 正确结构(注意字段名大小写和顺序):
bson.M{"type": "Point", "coordinates": []float64{116.4789, 39.9223}}—— 经度在前、纬度在后 - ❌ 常见错误:
{"lat": 39.9223, "lng": 116.4789}或[116.4789, 39.9223]—— 缺type字段,2dsphere索引创建会静默失败或不生效 - Go 中建议用结构体约束,避免运行时拼错字段:
type Location struct { Type string `bson:"type"` Coordinates []float64 `bson:"coordinates"` } type Store struct { Name string `bson:"name"` Location Location `bson:"location"` }
必须用 2dsphere 索引,不能用 2d
2d 是平面坐标系索引,算的是直线距离;真实地理场景(比如“5公里内门店”)必须用 2dsphere,否则 $near 可能返回错误排序,或 $maxDistance 单位失效。
- 创建索引代码(Go driver v1.12+):
indexModel := mongo.IndexModel{ Keys: bson.D{{"location", "2dsphere"}}, } _, err := collection.Indexes().CreateOne(ctx, indexModel) - 字段路径要完全匹配:如果 location 在子文档里,比如
address.location,索引键必须写成"address.location" - 验证是否生效:MongoDB Shell 中执行
db.stores.getIndexes(),确认输出里有"key" : { "location" : "2dsphere" }
查询必须用 $near + $geometry,且单位是米
即使索引建对了,查法不对照样出问题——$near 默认不启用球面计算,$maxDistance 单位也不是公里。
立即学习“go语言免费学习笔记(深入)”;
- 正确查询示例(找中心点 5 公里内,按距离升序):
filter := bson.M{ "location": bson.M{ "$near": bson.M{ "$geometry": bson.M{ "type": "Point", "coordinates": []float64{116.4789, 39.9223}, }, "$maxDistance": 5000, // 单位:米 }, }, } -
$near不支持$sort显式指定方向,它天然按距离由近到远排序;加$sort: {"location": 1}是冗余且可能干扰优化器 - 若需返回实际距离值(比如展示“距您 842 米”),必须用聚合管道 +
$geoNear阶段,$near查询本身不提供距离字段
Go 中容易漏掉的上下文与错误处理
很多性能问题或空结果,其实来自 Go 层的 context 超时或错误忽略,而不是 MongoDB 配置。
-
context.TODO()不能用于生产环境,必须传带超时的 context,比如context.WithTimeout(ctx, 5*time.Second) -
collection.Find()返回的*mongo.Cursor必须调用Close(),否则连接泄漏 - 检查
err不能只看nil:索引未建好时,$near查询可能返回mgo.ErrNotFound类似错误,但实际是索引缺失;建议先用db.collection.getIndexes()确认索引存在 - 坐标顺序极易搞反:OpenStreetMap / Google Maps 是
[纬度, 经度],MongoDB GeoJSON 是[经度, 纬度]—— 这个反直觉点,90% 的距离偏差都源于此


















