skip to Main Content

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(),
      );
}

2

Answers


  1. Chosen as BEST ANSWER

    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


  2. Change your where Firestore request to:

        .where("geohash", isLessThanOrEqualTo: range.upper)
        .where("geohash", isGreaterThanOrEqualTo: range.lower)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search