kosukesaigusa / geoflutterfire_plus

๐ŸŒ๐Ÿ’™๐Ÿ”ฅ geoflutterfire_plus allows your flutter apps to query geographic data saved in Cloud Firestore. This package is fork from GeoFlutterFire, and tried to be constantly maintained to work with latest Flutter SDK, Dart SDK, and other dependency packages.
https://pub.dev/packages/geoflutterfire_plus
MIT License
57 stars 7 forks source link

OrderBy not working #62

Closed hasseye closed 1 year ago

hasseye commented 1 year ago

Really cool what you're doing with this package. Unfortunately for Flutter, this is such a fragmented space and no packages appear to have got it right so far for Firestore GeoPoint Queries.

My big issue is being able to use the "OrderBy" feature. I switched to your package because you had a QueryBuilder, but once I try to do an OrderBy there, it hangs up again and nothing shows.

kosukesaigusa commented 1 year ago

@hasseye Thank you for using our package and creating an issue!

May I ask you to share your codes using orderBy in queryBuilder parameter? And if you find any error messages in your debug console, I also would like you to share the message or screenshot.

I would like to check and reproduce it, and try to solve the problem!

hasseye commented 1 year ago

@KosukeSaigusa Thanks for the fast response. Here's my code:

final CollectionReference<Map<String, dynamic>> collectionReference = firestore.collection('posts'); GeoFirePoint center = GeoFirePoint(GeoPoint(lat, lon));

final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> stream =
GeoCollectionReference<Map<String, dynamic>>(collectionReference)
  .subscribeWithin(
  center: center,
  radiusInKm: 200,
  field: 'location',
  queryBuilder: (Query<Map<String, dynamic>>? collection) => collection?.orderBy('createdAt', descending: false),
  geopointFrom: (data) => data['location']['geopoint'] as GeoPoint);

The queryBuilder is what's causing the issue. In the original GeoFlutterFire I guess orderBy didn't work because the way it was calling the geopoint query. Wasn't sure if you happened to find another way to resolve it. Per the official documentation "limit() and orderBy() are not supported at the moment. limit() could be used to limit docs inside each hash individually which would result in running limit on all 9 hashes inside the specified radius. orderBy() is first run on geohashes in the library, hence appending orderBy() with another field wouldn't produce expected results. Alternatively documents can be sorted on client side."

kosukesaigusa commented 1 year ago

@hasseye Thank you for your additional information!

I think currently orderBy is not available in our geoflutterfire_plus package for the same reason as original GeoFlutterFire...!

Because 9 different snapshots by 9 neighbor geohashes are merged on client side, so even if you can order them by orderBy for each snapshot, once they are merged, its order will be in correct as a whole result. I think it's better to sort them on client side after getting the query result.

But let me take time and think of the solution, if I find anything, I will let you know and implement it!

hasseye commented 1 year ago

@KosukeSaigusa I appreciate it. I believe the JS package recommended by the Flutter/Firebase team DO have ordering and limit that works, so not entirely sure how they do it, but may be something to look into. Happy to help too.

domidanke commented 1 year ago

Hey @KosukeSaigusa I am currently facing a similar issue relating to the querybuilder parameter.

My Event Document has the relevant location field with geohash and geopoint data inside it. The Document also has a Timestamp field called 'date'. When I am using querybuilder to filter out past events, I get no documents back. I set up an index in Firestore and I get no errors when running the queries but I have a feeling that the issue might be the inequality operator on the date field. Using 'isEqualTo' on a different field works for me. Do You know if inequality operators work? And if not, I'd be happy to help out making them work.

GeoCollectionReference(EventDocService().eventsCollection)
          .subscribeWithin(
            center: GeoFirePoint(centerGeoPoint),
            radiusInKm: radiusInKm,
            field: 'location',
            geopointFrom: (data) => data.location.geoPoint,
            strictMode: true,
            queryBuilder: (query) => query
                .orderBy('date')
                .where('date', isGreaterThanOrEqualTo: DateTime.now()),
          )
          .listen(_updateMarkers);
kosukesaigusa commented 1 year ago

@domidanke Thank you for your message and using geoflutter_plus package!

I set up an index in Firestore and I get no errors when running the queries but I have a feeling that the issue might be the inequality operator on the date field. Using 'isEqualTo' on a different field works for me.

Could you share the source codes which work without problems (and possibly screenshots of Cloud Firestore console of the collection/documents)?

I think, currently if you give queries which includes orderBy to queryBuilder, it will fail because of Cloud Firestore query restriction. Also, I confirmed that the same thing is reproduced when using GeoFlutterFire2 as well and we can find an explanation about the limitations here: https://github.com/beerstorm-net/geoflutterfire2#limitations.

I will try to come up with its solutions, but first, will write the similar explanation in geoflutterfire_plus README, and of course, if you find any ways to solve it, your future comments or PRs are always welcome๐Ÿ™Œ

domidanke commented 1 year ago

Thank you for the quick response @KosukeSaigusa. Firestore's restrictions really make this quite impossible for me right now. The link you sent confirms my issue. I will come back to this in the future :)

IncognitoGK9 commented 1 year ago

but even if orderBy or limit is not supported by Firebase for Geo Queries, the queryBuilder does not run if there is not orderBy (as one does a querybuilder without the orderBy, an error is thrown, meaning the queryBuilder parameter is redudant and not usable. Any of the codes below wont work:

    queryBuilder: (query) {
        return query.where(Str.UID,
            isNotEqualTo: FirebaseAuth.instance.currentUser!.uid);
        // .orderBy(Str.UID)
        // .orderBy(field);
      },
          queryBuilder: (query) {
        return query.where(Str.UID,
            isNotEqualTo: FirebaseAuth.instance.currentUser!.uid);
         .orderBy(Str.UID)
         .orderBy(field);
      },

in simple terms, the query builder expects a query in reference to the CollectionReference, on the other hand, Firebase expects the query to have an OrderBy, yet the OrderBy is not supported with GeoQueries. Even with just a Query without OrderBy should be supported as a parameter taken in by the GeoFlutterFire plus to emit a stream based on filtered documents.