Flutter中Firestore isNotEqualTo查询条件不生效问题排查
Flutter Firestore 搭配GeoFire使用时isNotEqualTo筛选失效问题
问题现象
- 为Firestore查询配置
isNotEqualTo筛选条件后无法返回符合规则的结果 - 单独测试
isNotEqualTo条件时可以正常运行,搭配GeoFire地理位置查询时失效 - 问题复现代码:
_setStream() async { var pos = await location.getLocation(); double lat = pos.latitude!; double lng = pos.longitude!; var ref = await FirebaseFirestore.instance.collection('now') .where('uid', isNotEqualTo: _user.uid).orderBy('uid'); GeoFirePoint center = geo.point(latitude: lat, longitude: lng); stream = radius.switchMap((rad) { var collectionReference = ref; return geo.collection(collectionRef: collectionReference).within( center: center, radius: rad, field: 'location', strictMode: true); }); setState(() { isLoading = false; }); stream = geo.collection(collectionRef: ref).within( center: center, radius: 2000, field: 'location', strictMode: true); stream!.listen((List<DocumentSnapshot> documentList) { documentList.forEach((element) { print("from data .......element"); print(element.data()); final data = element.data() as Map<String, dynamic>; final GeoPoint point = data['location']['geopoint']; print("from data .......latitude"); print(point.latitude); }); }); }
失效原因
- 错误给Query构造链式调用加了
await:Firestore的where、orderBy方法是同步返回Query对象的,不是异步操作,加await后拿到的对象不是可继续追加查询条件的Query实例,后续GeoFire追加地理位置查询逻辑时原有筛选条件会直接丢失。 - 复合查询排序规则冲突:Firestore有硬性限制,所有带不等值判断、范围判断的查询,第一个
orderBy必须对应第一个范围/不等筛选的字段。你手动提前写了orderBy('uid'),但GeoFire的within方法会自动在查询最前面追加基于location.geohash的范围筛选和排序,两者顺序直接冲突,查询逻辑不符合Firestore底层规则。 - 缺少对应复合索引:同时带地理位置范围筛选、uid不等值筛选的复合查询,需要在Firebase控制台创建匹配的复合索引才能正常返回结果,单独测试
isNotEqualTo时没有叠加地理位置范围查询,不需要复合索引所以能正常运行。 - 逻辑冗余冲突:你给
stream赋值完半径动态切换的switchMap逻辑后,又直接用固定半径2000的查询覆盖了stream,前面写的动态半径逻辑完全不会执行,也会导致查询状态混乱。
修复方案
- 去掉Query构造时多余的
await,同步构造基础查询,同时移除提前写的orderBy('uid'):
// 移除await和提前的orderBy,Query为同步构造对象 var ref = FirebaseFirestore.instance.collection('now') .where('uid', isNotEqualTo: _user.uid);
- 调整查询构造顺序:先把基础Query传给GeoFire生成带地理位置筛选的查询,再追加uid的排序逻辑,保证排序顺序符合Firestore规则。
- 删除重复覆盖
stream的冗余代码,根据业务需求二选一:要么保留radius.switchMap的动态半径逻辑,要么保留固定2000米半径的查询,不要重复给stream赋值。 - 第一次运行修正后的代码时,查看调试控制台输出的Firestore报错日志,按照提示创建对应的复合索引(覆盖
location.geohash、uid字段),等索引构建完成后查询即可正常返回结果。
内容的提问来源于stack exchange,提问作者Mohammed Ali
相关产品推荐
相关产品推荐

