必须为地理位置字段创建2dsphere索引,否则geonear等操作返回空数组;字段值须为db.geo.point格式;geonear需用db.command.geonear调用且不可与其他条件混用;坐标系须统一为wgs84。

uniCloud地理搜索必须建索引,否则查不到
不建地理位置索引,geoNear、geoWithin 等操作一律返回空数组,控制台无报错但数据就是不出现——这是最常被忽略的前提。uniCloud 的 Point 字段默认不带索引,哪怕你字段存的是合法经纬度,没索引就等于不可搜。
建法很简单:在 HBuilderX 中右键对应集合 → 「创建索引」→ 类型选 2dsphere,字段名填你的地理位置字段(比如 location),保存并上传。注意字段值必须是 db.Geo.Point(long, lat) 格式,不能是普通对象或字符串。
- 索引名称随意,但类型必须是
2dsphere(不是2d) - 如果字段名是嵌套的(如
address.geo),索引字段要写完整路径address.geo - 建完索引后,需等待 1–2 分钟才生效,别立刻测试
geoNear 查询必须用 db.command.geoNear,不能写在 where 对象里直接比
geoNear 是聚合阶段操作符,不是普通查询条件,所以不能像 { location: { $near: ... } } 那样写。前端直连或云函数中都必须用 db.command.geoNear 显式调用,且只能用于 where 的单个字段条件中。
正确写法:
const res = await db.collection('shops').where({
location: db.command.geoNear({
geometry: new db.Geo.Point(116.404, 39.915),
maxDistance: 5000
})
}).get()
-
geometry必须是db.Geo.Point实例,传数组或对象会静默失败 -
maxDistance单位是「米」,不是公里;不设则默认不限距离(但性能极差) - 不能同时用
geoNear和其他字段做and组合(如{ location: geoNear(...), status: 'open' }),得改用聚合管道
想按距离排序或加其他条件?必须切到聚合管道
前端 where().get() 不支持对 geoNear 结果再排序或叠加复杂逻辑。例如“查 3km 内营业中的咖啡馆,按距离升序排”,就得用聚合:
const res = await db.collection('shops').aggregate()
.geoNear({
distanceField: 'distance',
near: new db.Geo.Point(116.404, 39.915),
maxDistance: 3000,
spherical: true
})
.match({ status: 'open', category: 'cafe' })
.project({ distance: 1, name: 1, address: 1 })
.end()
-
distanceField是必填项,指定把距离存到哪个字段(后续可用来排序或展示) -
spherical: true必须加,否则地球曲率计算错误,百公里外的距离全是 0 -
match放在geoNear后面,才能过滤出的结果再筛,顺序不能反
真机调试时定位不准,大概率是坐标系没对齐
uni.getLocation 默认返回 gcj02(国测局坐标系),但腾讯/高德地图 SDK、uniCloud 地理索引都按 wgs84(GPS 原始坐标)处理。直接拿 gcj02 坐标去查,偏差可能达 500 米以上。
解决办法只有两个:
- 前端调用
uni.getLocation({ type: 'wgs84' })(仅 iOS 和部分安卓支持,微信小程序不支持) - 更通用的做法:在云函数里用腾讯地图逆地址解析 API 把
gcj02转成wgs84,再查库
别信“自动转换”或“SDK 内部处理”这种说法——uniCloud 数据库存的就是你写进去的坐标,它不会帮你猜你用的是哪种坐标系。










