Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter & firebase get docs by geohash

I'm trying to get a documents based on a geohash upper and lower bounds. 'Location A' is the location of a user, and we're trying to find other locations that are within the bounds of 'Location A' in firebase. I was following this tutorial

https://levelup.gitconnected.com/nearby-location-queries-with-cloud-firestore-e7f4a2f18f9d

and checking with this website

https://www.movable-type.co.uk/scripts/geohash.html

The coordinates of 'location A' are 52.462570419161594, -2.0120335164758725 and the coordinates of 'Location B' are 52.46648448588268, -1.9841125656313279. These are very close to eachother so, with the code below i'd assume that with the firebase query it'd return 'Location B' when querying from 'Location A's geohash but this isn't happening and it's because the getGeohashRange function is returning the wrong value but i'm not sure what i'm doing wrong

Location A geohash = 'gcqd6' Location B geohash = 'gcqd6'

The upper & lower that the getGeohashRange is returning = lower: "mpt5mf52n18z" upper: "mptmvc2wncyc"

This is the code & firebase query

// Get the geohash upper & lower bounds
GeoHashRange getGeohashRange({
  required double latitude,
  required double longitude,
  double distance = 12, // miles
}) {
  double lat = 0.0144927536231884; // degrees latitude per mile
  double lon = 0.0181818181818182; // degrees longitude per mile

  double lowerLat = latitude - lat * distance;
  double lowerLon = longitude - lon * distance;

  double upperLat = latitude + lat * distance;
  double upperLon = longitude + lon * distance;

  GeoHasher geo = GeoHasher();

  var lower = geo.encode(lowerLat, lowerLon);
  var upper = geo.encode(upperLat, upperLon);

  return GeoHashRange(lower: lower, upper: upper);
}

class GeoHashRange {
  late String upper;
  late String lower;

  GeoHashRange({
    required this.upper,
    required this.lower,
  })
}



// Query firebase for locations
Stream<List<Garage>> getLocalGarages(Position position) {
  GeoHashRange range = getGeohashRange(
    latitude: position.latitude,
    longitude: position.longitude,
  );

  var ref = _db
      .collection('garages')
      .where("geohash", isGreaterThan: range.upper)
      .where("geohash", isLessThan: range.lower);

  return ref.snapshots().map(
        (list) =>
            list.docs.map((doc) => Garage.fromJson(doc.data())).toList(),
      );
}
like image 278
chumberjosh Avatar asked Jan 20 '26 20:01

chumberjosh


2 Answers

Turns out theres a plugin that can actually help with this. This doc has some info https://firebase.google.com/docs/firestore/solutions/geoqueries#java and this is the plugin https://pub.dev/packages/geoflutterfire

This is my new code

Stream<List<Garage>> localGarages(Position position) {
  var ref = _db.collection('garages');

  GeoFirePoint center =
      geo.point(latitude: position.latitude, longitude: position.longitude);
  double radiusInKM = 20;

  return geo
      .collection(collectionRef: ref)
      .within(center: center, radius: radiusInKM, field: 'position')
      .map((x) => x.map((e) => Garage.fromJson(e.data()!)).toList());
}

There is an example of the 'position' field in the doc above

like image 132
chumberjosh Avatar answered Jan 23 '26 09:01

chumberjosh


Change your where Firestore request to:

    .where("geohash", isLessThanOrEqualTo: range.upper)
    .where("geohash", isGreaterThanOrEqualTo: range.lower)
like image 32
ABDO-AR Avatar answered Jan 23 '26 10:01

ABDO-AR



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!