You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Firestore查询中比对多字段以实现附近用户展示功能

附近用户功能实现方案

现有逻辑问题说明

你当前的_getNearbyUsers方法存在两个核心问题:

  • 没有返回符合StreamBuilder要求的Stream类型数据,无法直接驱动列表渲染
  • 距离计算逻辑没有和用户查询结果结合,没有做距离过滤

代码修改实现

1. 重写_getNearbyUsers方法

定义搜索半径,对查询到的活跃用户做距离过滤,返回符合要求的用户流:

// 搜索半径,单位为米,此处设置为5公里
const double _searchRadius = 5000;

Stream<List<DocumentSnapshot>> _getNearbyUsers() async* {
  // 未获取到当前用户位置时直接返回空列表
  if (_userLatitude == null || _userLongitude == null) {
    yield [];
    return;
  }
  // 监听活跃用户的实时更新
  await for (QuerySnapshot snapshot in usersRef.where('location', isEqualTo: "active").snapshots()) {
    List<DocumentSnapshot> nearbyUsers = [];
    String currentUid = (await FirebaseAuth.instance.currentUser()).uid;
    for (DocumentSnapshot doc in snapshot.documents) {
      // 跳过当前用户自身
      if (doc.documentID == currentUid) continue;
      double otherLat = doc.data['latitude'];
      double otherLng = doc.data['longitude'];
      // 计算两个用户的距离
      double distance = await Geolocator.distanceBetween(
        _userLatitude, 
        _userLongitude, 
        otherLat, 
        otherLng
      );
      // 符合半径要求的用户加入结果集
      if (distance <= _searchRadius) {
        doc.data['distance'] = distance;
        nearbyUsers.add(doc);
      }
    }
    yield nearbyUsers;
  }
}

2. 调整StreamBuilder适配新的数据流

因为现在返回的是过滤后的用户列表,需要对应修改判断逻辑:

StreamBuilder(
  stream: _getNearbyUsers(),
  builder: (context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(child: Text("加载中..."));
    }
    if (!snapshot.hasData || snapshot.data.isEmpty) {
      return const Center(child: Text("暂时没有附近的用户"));
    }
    return ListView.builder(
      padding: const EdgeInsets.only(top: 10),
      itemCount: snapshot.data.length,
      itemBuilder: (context, index) => _buildListUsers(context, snapshot.data[index])
    );
  },
)

3. 优化列表项渲染

可以在列表中展示用户距离,提升使用体验:

Widget _buildListUsers(BuildContext context, DocumentSnapshot document) {
  Users user = Users();
  user.id = document["id"];
  user.distance = document['distance'];
  
  return ListTile(
    onTap: () {
      Navigator.pushNamed(context, "/users", arguments: user);
    },
    title: Text(document['id']),
    subtitle: Text("距离:${(document['distance']/1000).toStringAsFixed(1)}km"),
  );
}

性能优化建议

如果你的应用用户量较大,全量查询所有活跃用户再过滤的方式性能会很低,可以采用geohash方案优化:

  • 写入用户位置时同步计算并存储对应经纬度的geohash字段
  • 查询时先通过geohash前缀过滤出大致处于目标范围内的用户,再做精确距离计算,可大幅减少需要遍历的文档数量

内容的提问来源于stack exchange,提问作者TonyCrudor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 04:24:05