用 bson.d 或 bson.m 显式构造地理查询,注意坐标顺序为[经度,纬度]、补全 type:"point"、创建2dsphere索引;polygon需闭合且逆时针;$near 用于 find 轻量排序,$geonear 用于 aggregate 返回距离,单位均为米。

如何用 Go 的 mongo-go-driver 构建地理位置查询?
Go 官方驱动 mongo-go-driver 不像 MongoDB Shell 那样直接支持 $near 或 $geoWithin 的“开箱即用”写法,必须手动构造 BSON 查询结构。核心是用 bson.D 或 bson.M 显式声明地理字段、坐标类型和查询操作符。
常见错误是把经纬度顺序搞反(MongoDB 要求 [经度, 纬度],不是常见的 [纬度, 经度]),或漏掉 type: "Point" 字段——这会导致索引失效或 location field must be an array or object 错误。
- 确保地理字段在集合中是标准 GeoJSON 格式:
{"type": "Point", "coordinates": [116.3974, 39.9093]} - 创建 2dsphere 索引必不可少:
db.collection.createIndex({"loc": "2dsphere"}),其中loc是你的地理字段名 - 查询时用
bson.D{{"loc", bson.D{{"$near", bson.D{{"$geometry", bson.D{{"type", "Point"}, {"coordinates", []float64{116.3974, 39.9093}}}}, {"$maxDistance", 1000}}}}}
为什么 $geoWithin + Polygon 总查不到数据?
根本原因通常是坐标环(ring)未闭合,或点顺序违反右手法则(counter-clockwise)。MongoDB 要求多边形外环坐标按逆时针排列,且首尾坐标必须完全相同。
Go 中构建 Polygon 时容易忽略闭合逻辑:你传入的 [][]float64 如果没手动追加第一个点到末尾,mongo-go-driver 不会自动补全,查询会静默返回空结果。
- 正确 Polygon 示例:
[][]float64{{116.0, 39.0}, {117.0, 39.0}, {117.0, 40.0}, {116.0, 40.0}, {116.0, 39.0}} - 查询结构应为:
bson.M{"loc": bson.M{"$geoWithin": bson.M{"$geometry": bson.M{"type": "Polygon", "coordinates": [][]interface{}{polygonCoords}}}}} - 调试建议:先在 mongosh 中用同样坐标跑一遍
$geoWithin,确认数据存在且几何合法
Find 和 Aggregate 哪个更适合地理距离排序?
单纯按距离排序用 Find + $near 更轻量;需要叠加其他条件(比如“附近3公里内状态为 active 的店铺,再按评分倒序”)就必须用 Aggregate —— 因为 $near 只能出现在 pipeline 第一阶段,且不能和其他 $sort 混用。
一个典型陷阱是:在 Aggregate 中误用 $sort 替代 $near,结果发现没有地理索引加速,查询变慢十倍以上。
-
Find场景:仅需最近 N 个点,如limit(10)+$near -
Aggregate场景:需组合过滤、投影、分组,例如先$geoWithin再$match状态,最后$addFields计算距离 - 注意:用
$geoNear替代$near在 aggregate 中才能返回距离字段distance
坐标系单位混乱导致距离偏差巨大
MongoDB 的 2dsphere 索引默认按 WGS84 椭球体计算距离,单位是**米**;但很多人误以为是千米或角度值,结果设置 $maxDistance: 5 却想查 5 公里——实际只查了 5 米。
另一个坑是混合使用不同坐标系:如果原始数据存的是 GCJ-02(火星坐标),而你用 WGS84 坐标去查,偏差可达 500 米以上,尤其在高德/百度地图生态中很常见。
- 统一坐标系:入库前就转成 WGS84,或在应用层做一次纠偏(如用
golang-geo库) - 验证单位:
$maxDistance和$geoNear.distanceField返回值都是米,别除以 1000 后再比较 - 调试技巧:用
db.collection.find().limit(1).pretty()看实际存储的coordinates数值,对比查询时传入的是否一致
地理查询真正难的不是语法,而是坐标精度、索引有效性、单位一致性这三件事叠在一起出错时,现象往往只是“查不到”,而不是报错。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











