within method

Stream<List<DocumentSnapshot<Object?>>> within({
  1. required GeoFirePoint center,
  2. required double radius,
  3. required String field,
  4. bool strictMode = false,
})

query firestore documents based on geographic radius from geoFirePoint center field specifies the name of the key in the document

Implementation

Stream<List<DocumentSnapshot>> within({
  required GeoFirePoint center,
  required double radius,
  required String field,
  bool strictMode = false,
}) {
  final precision = Util.setPrecision(radius);
  final centerHash = center.hash.substring(0, precision);
  final area = GeoFirePoint.neighborsOf(hash: centerHash)..add(centerHash);

  Iterable<Stream<List<DistanceDocSnapshot>>> queries = area.map((hash) {
    final tempQuery = _queryPoint(hash, field);
    return _createStream(tempQuery).map((QuerySnapshot querySnapshot) {
      return querySnapshot.docs
          .map((element) => DistanceDocSnapshot(element, null))
          .toList();
    });
  });

  Stream<List<DistanceDocSnapshot>> mergedObservable =
      mergeObservable(queries);

  var filtered = mergedObservable.map((List<DistanceDocSnapshot> list) {
    var mappedList = list.map((DistanceDocSnapshot distanceDocSnapshot) {
      // split and fetch geoPoint from the nested Map
      final fieldList = field.split('.');
      final data =
          distanceDocSnapshot.documentSnapshot.data() as Map<String, dynamic>;
      var geoPointField = data[fieldList[0]];
      if (fieldList.length > 1) {
        for (int i = 1; i < fieldList.length; i++) {
          geoPointField = geoPointField[fieldList[i]];
        }
      }
      final GeoPoint geoPoint = geoPointField['geopoint'];
      distanceDocSnapshot.distance =
          center.distance(lat: geoPoint.latitude, lng: geoPoint.longitude);
      return distanceDocSnapshot;
    });

    final filteredList = strictMode
        ? mappedList
            .where((DistanceDocSnapshot doc) =>
                    doc.distance! <=
                    radius * 1.02 // buffer for edge distances;
                )
            .toList()
        : mappedList.toList();
    filteredList.sort((a, b) {
      final distA = a.distance!;
      final distB = b.distance!;
      final val = (distA * 1000).toInt() - (distB * 1000).toInt();
      return val;
    });
    return filteredList.map((element) => element.documentSnapshot).toList();
  });
  return filtered.asBroadcastStream();
}