从 Google 云 Firestore 中非常快速地获取数据

Fetching data really fast from Google cloud firestore

我正在制作一个 flutter 应用程序,我正在使用 cloud firestore 作为我的在线数据库。我的应用程序中的一项功能是寻找附近的用户并在屏幕上的自定义小部件中向当前用户显示他们的个人资料。我这样做的方法是获取当前用户的位置(实时位置或保存在数据库中的地址),然后遍历我的数据库集合中的每个用户以获取用户。我从存储的数据中获取用户的地址,使用距离矩阵 API 计算距离,然后如果距离小于特定数字(例如 10000 米),我为用户创建个人资料小部件以显示它屏幕。

有2个问题:

1- 如果我的用户数量增加(例如一百万用户),通过检查每个用户详细信息并计算距离,可能需要很长时间才能在屏幕上显示结果。现在,我只有 20 个用户用于测试目的,当我搜索附近的用户时,结果可能需要 30 秒才能显示在屏幕上。

2- 在网速较慢的情况下,等待时间可能会长得多,而且它会为这个简单的任务使用大量用户数据。

如何改进此功能并使其更快?

(我目前的想法是根据用户的位置在不同的文档中划分用户,然后使用当前用户的位置仅浏览其中一个文档。问题是如何有效地划分地址并找到要查找的最佳地址。)

下面是我找到附近用户并将他们添加到我传递给自定义小部件的列表的代码 class。

final List<UserBoxDesign> listOfBoxes = [];
final FirebaseUser currentUser = await auth.currentUser();
final String currentUserId = currentUser.uid;
if (_userLocationSwitchValue == false) { //use default address of the user
  currentUserAddress = await _databaseManagement.getUserCollectionValues(
      currentUserId, "address");
} else {
  //currentUserAddress = //to do, get device location here.
}
if (_searchValue == SearchValues.Users) {
  final List<String> userIds = await _databaseManagement.getUserIds();
  for (String id in userIds) {
    final String otherUserLocations =
        await _databaseManagement.getUserCollectionValues(id, "address");
    final String distanceMeters = await _findDistanceGoogleMaps(
        currentUserAddress, otherUserLocations);
    if (distanceMeters == "Address can't be calculated" ||
        distanceMeters == "Distance is more than required by user") {
      //if it's not possible to calculate the address then just don't do anything with that.
    } else {
      final double distanceValueInKilometers = (double.parse(
                  distanceMeters) /
              1000)
          .roundToDouble(); 
      final String userProfileImageUrl =
          await _databaseManagement.getUserCollectionValues(id, "image");
      final String username =
          await _databaseManagement.getUserCollectionValues(id, "username");
      listOfBoxes.add(
        UserBoxDesign( //it creates a custom widget for user if user is nearby
          userImageUrl: userProfileImageUrl,
          distanceFromUser: distanceValueInKilometers,
          userId: id,
          username: username,
        ),
      ); //here we store the latest values inside the reserved data so when we create the page again, the value will be the reservedData value which is not empty anymore

    }
    print(listOfBoxes);
  }
  listOfBoxes.sort((itemA,itemB)=>itemA.distanceFromUser.compareTo(itemB.distanceFromUser)); //SORTs the items from closer to more far from user (we can reverse it to far comes first and close goes last)
  setState(() {
    _isSearchingForUser = false;
  });
  return listOfBoxes;

这是我计算起始地址和目标地址之间距离的代码。

Future<String> _findDistanceGoogleMaps(
  String originAddress, String destinationAddress) async {
final String url =
    "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=$originAddress&destinations=$destinationAddress&key=$GoogleMapsAPIKey";
try {
  final response = await http.get(url);
  final responseDecoded = json.decode(response.body);

  final distanceInMeters = double.parse(responseDecoded["rows"][0]
          ["elements"][0]["distance"]["value"]
      .toString()); //this is the value in meters always so for km , divide by 1000.
  if (distanceInMeters < 100000) {
    return distanceInMeters.toString();
  } else {
    return "Distance is more than required by user";
  }
} catch (e) {
  return "Address can't be calculated";
}

}

this is how my screen looks when I find nearby users.

如果您给出代码示例,将很容易回答。 我可以建议(我们有类似的任务)使用坐标经度和纬度并在您的范围内发出请求。

所以你不需要距离矩阵API(我认为它会很贵)而且你的查询会快速且便宜。

我用谷歌搜索并在这里找到了答案

==问题更新后==

  1. 您尝试使用屏幕内的所有逻辑并同步执行。因为你有这么长的渲染时间。 您计算用户设备上的所有内容并传递给小部件 return listOfBoxes; 相反,您可以尝试使用 Streambuilder,示例在这里

  2. 以这样的方式组织数据库中的数据,以便您可以针对自己的目的提出请求:"Find all users within X range sorted by distance AND ..."。 在这种情况下,Firebase 会非常快速地执行此操作并将数据异步传递给您的 Streambuilder。 我想您可以保留经度、纬度并使用它们而不是地址。

抱歉,我无法重写您的代码,信息不足。看看的例子,有一个很好的例子。

==更新2==

包裹https://pub.dev/packages/geoflutterfire 允许将地理数据存储到 Firestore 以及如何发出请求

// Create a geoFirePoint
GeoFirePoint center = geo.point(latitude: 12.960632, longitude: 77.641603);

// get the collection reference or query
var collectionReference = _firestore.collection('locations');

double radius = 50;
String field = 'position';

Stream<List<DocumentSnapshot>> stream = geo.collection(collectionRef: collectionReference)
                                        .within(center: center, radius: radius, field: field);