使用Geoflutterfire2查询Firebase附近用户的首次查询异常问题
问题解决:Geoflutterfire2首次查询仅返回当前用户及替代方案
一、Geoflutterfire2问题修复
你的问题核心是首次查询取到了本地缓存的当前用户数据,而完整的服务器数据在后续流发射中才返回。以下是修复后的代码:
import 'package:geoflutterfire2/geoflutterfire2.dart'; import 'package:firebase_auth/firebase_auth.dart'; final geo = GeoFlutterFire(); Future<List<UsersRecord>?> getNearbyUsers( LatLng centerPoint, double maxDistance, ) async { GeoFirePoint center = geo.point( latitude: centerPoint.latitude, longitude: centerPoint.longitude); var collectionReference = FirebaseFirestore.instance.collection('users'); double radius = maxDistance; String field = 'location'; String currentUserId = FirebaseAuth.instance.currentUser!.uid; // 等待第一个非仅含当前用户的快照,避免缓存数据干扰 var snapshots = await geo .collection(collectionRef: collectionReference) .within(center: center, radius: radius, field: field, strictMode: true) .firstWhere( (snapshots) => snapshots.length != 1 || snapshots.first.id != currentUserId, orElse: () => [], ).timeout(const Duration(seconds: 5), onTimeout: () => []); // 过滤掉当前用户 return snapshots .where((snapshot) => snapshot.id != currentUserId) .map((snapshot) => UsersRecord.fromSnapshot(snapshot)) .toList(); }
关键修改点:
- 添加当前用户ID过滤,确保结果中不含自身
- 使用
firstWhere替代first,等待包含完整数据的快照 - 增加超时机制,防止无限等待
二、无需Geoflutterfire2的一次性地理查询方案
直接通过Geohash范围查询+手动距离计算实现,无需依赖第三方库:
import 'package:geohash/geohash.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'dart:math'; Future<List<UsersRecord>?> getNearbyUsersWithoutGeoFlutterFire( LatLng centerPoint, double maxDistance, // 单位:千米 ) async { // 1. 根据半径确定Geohash精度(可根据需求调整) int precision = 5; // 精度5对应约1.2km范围,覆盖1km查询需求 String centerGeohash = Geohash.encode(centerPoint.latitude, centerPoint.longitude, precision: precision); // 2. 获取所有相邻的Geohash前缀 Set<String> nearbyHashes = {centerGeohash}; nearbyHashes.addAll(Geohash.neighbors(centerGeohash)); // 3. 查询Firestore中包含这些Geohash前缀的用户 QuerySnapshot snapshot = await FirebaseFirestore.instance .collection('users') .where('location.geohash', whereIn: nearbyHashes.toList()) .get(GetOptions(source: Source.server)); // 强制从服务器获取数据,避免缓存 // 4. 手动计算距离并过滤结果 List<UsersRecord> nearbyUsers = []; String currentUserId = FirebaseAuth.instance.currentUser!.uid; for (var doc in snapshot.docs) { if (doc.id == currentUserId) continue; // 跳过当前用户 GeoPoint geopoint = doc['location']['geopoint']; LatLng docLocation = LatLng(geopoint.latitude, geopoint.longitude); double distance = _calculateHaversineDistance(centerPoint, docLocation); if (distance <= maxDistance) { nearbyUsers.add(UsersRecord.fromSnapshot(doc)); } } return nearbyUsers; } // 哈弗辛公式计算两点间距离(单位:千米) double _calculateHaversineDistance(LatLng a, LatLng b) { const double earthRadius = 6371; double latDiff = _degreesToRadians(b.latitude - a.latitude); double lonDiff = _degreesToRadians(b.longitude - a.longitude); double aLatRad = _degreesToRadians(a.latitude); double bLatRad = _degreesToRadians(b.latitude); double temp = sin(latDiff / 2) * sin(latDiff / 2) + sin(lonDiff / 2) * sin(lonDiff / 2) * cos(aLatRad) * cos(bLatRad); double c = 2 * atan2(sqrt(temp), sqrt(1 - temp)); return earthRadius * c; } double _degreesToRadians(double degrees) { return degrees * (pi / 180); }
方案说明:
- 通过Geohash前缀缩小查询范围,减少需要计算距离的文档数量
- 使用哈弗辛公式精确计算两点间直线距离
- 强制从服务器获取数据,避免缓存导致的不完整结果
- 直接过滤当前用户,无需额外处理
内容的提问来源于stack exchange,提问作者user23363377
相关产品推荐
相关产品推荐

