Coder Social home page Coder Social logo

kosukesaigusa / geoflutterfire_plus Goto Github PK

View Code? Open in Web Editor NEW
55.0 5.0 4.0 422 KB

๐ŸŒ๐Ÿ’™๐Ÿ”ฅ 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.

Home Page: https://pub.dev/packages/geoflutterfire_plus

License: MIT License

Dart 97.41% Kotlin 0.11% Ruby 1.71% Swift 0.73% Objective-C 0.04%
cloudfirestore dart flutter flutterfire geopoint geoquery firebase firestore

geoflutterfire_plus's Introduction

geoflutterfire_plus ๐ŸŒ

version MIT License PRs Welcome

geoflutterfire_plus allows your Flutter apps to query geographic data saved in Cloud Firestore.

This package is forked from GeoFlutterFire and whole codes are redesigned with some new features, and will be maintained to work with latest Flutter SDK, Dart SDK, and other dependency packages.

example

Getting started

Prerequisites are following.

Dart: '>=2.17.0 <3.0.0'
Flutter: '>=2.10.0'

Run this command in your project.

flutter pub add geoflutterfire_plus

Or, add dependency to your pubspec.yaml.

dependencies:
  geoflutterfire_plus: <latest-version>

Geohash and geo queries

Refer to Firebase official document Geo queries to understand what Geohash is, why you need to save geo location as Geohash, and how to query them. It will also help you understand limitations of using Geohashes for querying locations.

Save geo data

In order to save geo data as documents of Cloud Firestore, use GeoFirePoint. GeoFirePoint.data gives geopoint (GeoPoint type defined in cloud_firestore package) and Geohash string.

// Define GeoFirePoint by instantiating GeoFirePoint with latitude and longitude.
final GeoFirePoint geoFirePoint = GeoFirePoint(GeoPoint(35.681236, 139.767125));

// Gets GeoPoint instance and Geohash string as Map<String, dynamic>.
final Map<String, dynamic> data = geoFirePoint.data;

// {geopoint: Instance of 'GeoPoint', geohash: xn76urx66}
print(data);

GeoCollectionReference instance provides add method to create a new document in the collection (internally, just calling add method of cloud_firestore).

// Adds new documents to locations collection.
GeoCollectionReference<Map<String, dynamic>>(
  FirebaseFirestore.instance.collection('locations'),
).add(<String, dynamic>{
  'geo': geoFirePoint.data,
  'name': name,
  'isVisible': true,
});

Or, you can just call add or set method of cloud_firestore to save the data. For example,

// Adds new documents to locations collection.
FirebaseFirestore.instance.collection('locations').add(
  <String, dynamic>{
    'geo': geoFirePoint.data,
    'name': 'Tokyo Station',
    'isVisible': true,
  },
);

The created document would be like the screenshot below. Geohash string (geohash) and Cloud Firestore GeoPoint data (geopoint) is saved in geo field as map type.

Cloud Firestore

In order to set or update the pair of latitude and longitude as cloud_firestore GeoPoint and also Geohash string on the specified document's given field, GeoCollectionReference.set or GeoCollectionReference.updatePoint methods are available.

// Sets a new document by giving geoFirePoint.data to 'geo' field.
GeoCollectionReference(FirebaseFirestore.instance.collection('locations'))
    .set(
  id: 'your-document-id',
  data: {
    'geo': geoFirePoint.data,
    'foo': 'foo',
    'bar': 'bar',
  },
  options: SetOptions(merge: true),
);

// Updates an existing document's 'geo' field by giving GeoPoint instance.
GeoCollectionReference(FirebaseFirestore.instance.collection('locations'))
    .updatePoint(
  id: 'your-document-id',
  field: 'geo',
  geopoint: GeoPoint(35.681236, 139.767125),
);

Query geo data

In order to query location documents within a 50 km radius of a given point, you will write query like the following:

Basic query

// cloud_firestore [GeoPoint] of Tokyo Station.
const GeoPoint tokyoStation = GeoPoint(35.681236, 139.767125);

// Center of the geo query.
final GeoFirePoint center = GeoFirePoint(tokyoStation);

// Detection range from the center point.
const double radiusInKm = 50;

// Field name of Cloud Firestore documents where the geohash is saved.
const String field = 'geo';
// Reference to locations collection.
final CollectionReference<Map<String, dynamic>> collectionReference =
    FirebaseFirestore.instance.collection('locations');

// Function to get GeoPoint instance from Cloud Firestore document data.
GeoPoint geopointFrom(Map<String, dynamic> data) =>
     (data['geo'] as Map<String, dynamic>)['geopoint'] as GeoPoint;
// Streamed document snapshots of geo query under given conditions.
final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> stream =
    GeoCollectionReference<Map<String, dynamic>>(collectionReference)
        .subscribeWithin(
  center: center,
  radiusInKm: radiusInKm,
  field: field,
  geopointFrom: geopointFrom,
);

Using withConverter

If you would like to use withConverter to type-safely write query, first, you need to define its entity class and factory constructors.

/// An entity of Cloud Firestore location document.
class Location {
  Location({
    required this.geo,
    required this.name,
    required this.isVisible,
  });

  factory Location.fromJson(Map<String, dynamic> json) => Location(
        geo: Geo.fromJson(json['geo'] as Map<String, dynamic>),
        name: json['name'] as String,
        isVisible: (json['isVisible'] ?? false) as bool,
      );

  factory Location.fromDocumentSnapshot(DocumentSnapshot documentSnapshot) =>
      Location.fromJson(documentSnapshot.data()! as Map<String, dynamic>);

  final Geo geo;
  final String name;
  final bool isVisible;

  Map<String, dynamic> toJson() => <String, dynamic>{
        'geo': geo.toJson(),
        'name': name,
        'isVisible': isVisible,
      };
}

/// An entity of `geo` field of Cloud Firestore location document.
class Geo {
  Geo({
    required this.geohash,
    required this.geopoint,
  });

  factory Geo.fromJson(Map<String, dynamic> json) => Geo(
        geohash: json['geohash'] as String,
        geopoint: json['geopoint'] as GeoPoint,
      );

  final String geohash;
  final GeoPoint geopoint;

  Map<String, dynamic> toJson() => <String, dynamic>{
        'geohash': geohash,
        'geopoint': geopoint,
      };
}

Then, define typed collection reference.

/// Reference to the collection where the location data is stored.
final typedCollectionReference =
    FirebaseFirestore.instance.collection('locations').withConverter<Location>(
          fromFirestore: (ds, _) => Location.fromDocumentSnapshot(ds),
          toFirestore: (obj, _) => obj.toJson(),
        );

// Function to get GeoPoint instance from Location instance.
GeoPoint geopointFrom: (Location location) => location.geo.geopoint;

You can write query in the same way as the first example.

// Streamed typed document snapshots of geo query under given conditions.
final Stream<List<DocumentSnapshot<Location>>> stream =
    GeoCollectionReference<Location>(typedCollectionReference).subscribeWithin(
  center: center,
  radiusInKm: radiusInKm,
  field: field,
  geopointFrom: geopointFrom,
);

Custom query conditions

If you would like to add custom query conditions, queryBuilder parameter of fetchWithin (fetchWithinWithDistance) / subscribeWithin (subscribeWithinWithDistance) method is available.

For example, when you filter only isVisible field is true documents, your queryBuilder would be like this:

// Custom query condition.
Query<Location> queryBuilder(Query<Location> query) =>
    query.where('isVisible', isEqualTo: true);

Then, just give the queryBuilder to the parameter of fetchWithin (fetchWithinWithDistance) / subscribeWithin (subscribeWithinWithDistance) method.

๐Ÿšจ Note: Custom query condition may require a composite index. If the index is not created, you will see the "[cloud_firestore/failed-precondition] The query requires an index..." error from Firestore on the debug console. You can create the index by clicking the link in the error message.

// Streamed typed document snapshots of geo query under custom query conditions.
final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> stream =
    GeoCollectionReference<Map<String, dynamic>>(typedCollectionReference)
        .subscribeWithin(
  center: center,
  radiusInKm: radiusInKm,
  field: field,
  geopointFrom: geopointFrom,
  // Specify queryBuilder parameter here.
  queryBuilder: queryBuilder,
);

๐Ÿšจ Limitation: currently limit and orderBy queries are not supported because of the geo hash query algorithm and Cloud Firestore query limitations. Alternatively documents can be sorted on client side after getting the data (documents).

Examples

If you would like to try out the features, refer to the example project.

geoflutterfire_plus's People

Contributors

dai10512 avatar dependabot[bot] avatar iabdousd avatar king-kazu39 avatar kokorinosoba avatar kosukesaigusa avatar kurczaak avatar naokiwakata avatar shvn-iwa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

geoflutterfire_plus's Issues

'isCacheFirst' not working

Hi,
in my previous PR I've implemented the isCacheFirst functionality, however it's not working as expected. I haven't tested the implementation well enough. This time I did some tests with debugging and it seems to work correct. Let me know what you think, here's my PR:
#203

PS.
Sorry for the inconvenience, I promise to test my code better next time

QueryBuilder not returning any results

geoflutterfire_plus: ^0.0.21

When trying to inject additional query, I am not getting any results. When removing queryBuilder, I am getting all results.

Code:

var res =
      await GeoCollectionReference<Map<String, dynamic>>(collectionReference)
          .subscribeWithin(
            center: center,
            radiusInKm: radiusInKm,
            field: field,
            geopointFrom: geopointFrom,
            queryBuilder: (query) => query.where('archived', isEqualTo: false),
          )
          .first;

  final obj =
      res.map((docSnapshot) => Post.fromDocumentSnapshot(docSnapshot)).toList();

  return obj;

nor with fetchWithin

var res =
      await GeoCollectionReference<Map<String, dynamic>>(collectionReference)
          .fetchWithin(
    center: center,
    radiusInKm: radiusInKm,
    field: field,
    geopointFrom: geopointFrom,
    queryBuilder: (query) => query.where('archived', isEqualTo: false),
  );

i've tested it further because i thought it is something with my query, but passing null to query doesn't also work(I saw an example proj where null should get all values as well).

var res =
      await GeoCollectionReference<Map<String, dynamic>>(collectionReference)
          .fetchWithin(
    center: center,
    radiusInKm: radiusInKm,
    field: field,
    geopointFrom: geopointFrom,
    queryBuilder: (query) => null,
  );

Using queryBuilder negates the values and returns empty

If I pass a querybuilder to filter out values from the collection, the returns values are empty.
If I remove the query, values are returned. I need to return values based on the query:

var collectionReference =
     FirebaseFirestore.instance.collection(Str.BODA_REGISTRATION_COLLECTION);
 // .where(Str.UID, isNotEqualTo: FirebaseAuth.instance.currentUser!.uid); (this is not allowed, should be made to be allowed

 double radiusInKm = 10;
 String field = Str.GEOFIREPOINT_DATA;

 GeoPoint geopointFrom(Map<String, dynamic> data) =>
     (data[field] as Map<String, dynamic>)['geopoint'] as GeoPoint;

 final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> stream =
     GeoCollectionReference<Map<String, dynamic>>(collectionReference)
         .subscribeWithin(
   center: center,
   radiusInKm: radiusInKm,
   field: field,
   geopointFrom: geopointFrom,
//with the commented lines below, when uncommented, the list is empty, when commented, there are values. The data in firebase is to return all except for the one with a filter as shown. 
   // queryBuilder: (query) {
   //   return query
   //       .where(Str.UID,
   //           isNotEqualTo: FirebaseAuth.instance.currentUser!.uid)
   //       .orderBy(Str.UID)
   //       .orderBy(field);
   // },
 );
 
 await for (List<DocumentSnapshot<Map<String, dynamic>>> bodaList
     in stream) {
   final distances = bodaList.map((boda) {
     final bodaLocation = geopointFrom(boda.data()!);
     final double distance =
         center.distanceBetweenInKm(geopoint: bodaLocation);

     return distance * 1000;
   }).toList();

Possibly, have an updated documentation on how query filters work with GeoFlutterFire_plus with examples based on the approach I have up there. Or modify the package to include use of QuerySnapShot and show examples

Please update to rxdart ^0.28.0!!!

Because no versions of geoflutterfire_plus match >0.0.24 <0.1.0 and geoflutterfire_plus 0.0.24 depends on rxdart ^0.27.1, geoflutterfire_plus ^0.0.24 requires rxdart ^0.27.1.
And because flutter_google_places_hoc081098 >=2.0.0 depends on rxdart ^0.28.0, geoflutterfire_plus ^0.0.24 is incompatible with flutter_google_places_hoc081098 >=2.0.0.
So, because gather depends on both flutter_google_places_hoc081098 ^2.0.0 and geoflutterfire_plus ^0.0.24, version solving failed.
exit code 1

How many documents are queried?

In the documentation:

๐Ÿšจ Limitation: currently limit and orderBy queries are not supported because of the geo hash query algorithm and Cloud Firestore query limitations. Alternatively documents can be sorted on client side after getting the data (documents).

I would like to ask, how many documents are queried maximum?

hello I can't see the markers

hello, I just copy paste your examples and other files and just changed geo points, but I can't see any marker in my map I also checked with zoom out but still there's not thing show. I checked the connection with my firebase by adding new location and it worked well. Can you help me to see the markers?

Thank you, and your project is so amazing this is the exact project what I was looking for!!

screen capture of ios
screen capture of firebase

park_map.dart

import 'package:cloud_firestore/cloud_firestore.dart';
//import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:geoflutterfire_plus/geoflutterfire_plus.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:rxdart/rxdart.dart';

import '../locations/add_location.dart';
//import '../firebase_options.dart';
import '../locations/set_or_delete_location.dart';

/// Tokyo Station location for demo.
const _tokyoStation = LatLng(48.573405, 7.752111);

/// Reference to the collection where the location data is stored.
/// `withConverter` is available to type-safely define [CollectionReference].
final _collectionReference = FirebaseFirestore.instance.collection('locations');

/// Geo query geoQueryCondition.
class _GeoQueryCondition {
  _GeoQueryCondition({
    required this.radiusInKm,
    required this.cameraPosition,
  });

  final double radiusInKm;
  final CameraPosition cameraPosition;
}

class ParkMap extends StatefulWidget {
  const ParkMap({super.key});

  @override
  ParkMapState createState() => ParkMapState();
}

/// Example page using [GoogleMap].
class ParkMapState extends State<ParkMap> {
  /// [Marker]s on Google Maps.
  Set<Marker> _markers = {};

  /// [BehaviorSubject] of currently geo query radius and camera position.
  final _geoQueryCondition = BehaviorSubject<_GeoQueryCondition>.seeded(
    _GeoQueryCondition(
      radiusInKm: _initialRadiusInKm,
      cameraPosition: _initialCameraPosition,
    ),
  );

  /// [Stream] of geo query result.
  late final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> _stream =
      _geoQueryCondition.switchMap(
    (geoQueryCondition) =>
        GeoCollectionReference(_collectionReference).subscribeWithin(
      center: GeoFirePoint(
        GeoPoint(
          _cameraPosition.target.latitude,
          _cameraPosition.target.longitude,
        ),
      ),
      radiusInKm: geoQueryCondition.radiusInKm,
      field: 'geo',
      geopointFrom: (data) =>
          (data['geo'] as Map<String, dynamic>)['geopoint'] as GeoPoint,
      strictMode: true,
    ),
  );

  /// Updates [_markers] by fetched geo [DocumentSnapshot]s.
  void _updateMarkersByDocumentSnapshots(
    List<DocumentSnapshot<Map<String, dynamic>>> documentSnapshots,
  ) {
    final markers = <Marker>{};
    for (final ds in documentSnapshots) {
      final id = ds.id;
      final data = ds.data();
      if (data == null) {
        continue;
      }
      final name = data['name'] as String;
      final geoPoint =
          (data['geo'] as Map<String, dynamic>)['geopoint'] as GeoPoint;
      markers.add(_createMarker(id: id, name: name, geoPoint: geoPoint));
    }
    debugPrint('๐Ÿ“ markers count: ${markers.length}');
    setState(() {
      _markers = markers;
    });
  }

  /// Creates a [Marker] by fetched geo location.
  Marker _createMarker({
    required String id,
    required String name,
    required GeoPoint geoPoint,
  }) =>
      Marker(
        markerId: MarkerId('(${geoPoint.latitude}, ${geoPoint.longitude})'),
        position: LatLng(geoPoint.latitude, geoPoint.longitude),
        infoWindow: InfoWindow(title: name),
        onTap: () => showDialog<void>(
          context: context,
          builder: (context) => SetOrDeleteLocationDialog(
            id: id,
            name: name,
            geoFirePoint: GeoFirePoint(
              GeoPoint(geoPoint.latitude, geoPoint.longitude),
            ),
          ),
        ),
      );

  /// Current detecting radius in kilometers.
  double get _radiusInKm => _geoQueryCondition.value.radiusInKm;

  /// Current camera position on Google Maps.
  CameraPosition get _cameraPosition => _geoQueryCondition.value.cameraPosition;

  /// Initial geo query detection radius in km.
  static const double _initialRadiusInKm = 10;

  /// Google Maps initial camera zoom level.
  static const double _initialZoom = 10;

  /// Google Maps initial target position.
  static final LatLng _initialTarget = LatLng(
    _tokyoStation.latitude,
    _tokyoStation.longitude,
  );

  /// Google Maps initial camera position.
  static final _initialCameraPosition = CameraPosition(
    target: _initialTarget,
    zoom: _initialZoom,
  );

  @override
  void dispose() {
    _geoQueryCondition.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          GoogleMap(
            zoomControlsEnabled: false,
            myLocationButtonEnabled: false,
            initialCameraPosition: _initialCameraPosition,
            onMapCreated: (_) =>
                _stream.listen(_updateMarkersByDocumentSnapshots),
            markers: _markers,
            circles: {
              Circle(
                circleId: const CircleId('value'),
                center: LatLng(
                  _cameraPosition.target.latitude,
                  _cameraPosition.target.longitude,
                ),
                // multiple 1000 to convert from kilometers to meters.
                radius: _radiusInKm * 1000,
                fillColor: Colors.black12,
                strokeWidth: 0,
              ),
            },
            onCameraMove: (cameraPosition) {
              debugPrint('๐Ÿ“ท lat: ${cameraPosition.target.latitude}, '
                  'lng: ${cameraPosition.target.latitude}');
              _geoQueryCondition.add(
                _GeoQueryCondition(
                  radiusInKm: _radiusInKm,
                  cameraPosition: cameraPosition,
                ),
              );
            },
            onLongPress: (latLng) => showDialog<void>(
              context: context,
              builder: (context) => AddLocationDialog(latLng: latLng),
            ),
          ),
          Container(
            width: double.infinity,
            margin: const EdgeInsets.only(top: 64, left: 16, right: 16),
            padding: const EdgeInsets.all(16),
            decoration: const BoxDecoration(
              color: Colors.black38,
              borderRadius: BorderRadius.all(Radius.circular(8)),
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text(
                  'Debug window',
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  'Currently detected count: '
                  '${_markers.length}',
                  style: const TextStyle(color: Colors.white),
                ),
                const SizedBox(height: 8),
                Text(
                  'Current radius: '
                  '${_radiusInKm.toStringAsFixed(1)} (km)',
                  style: const TextStyle(color: Colors.white),
                ),
                const SizedBox(height: 8),
                Slider(
                  value: _radiusInKm,
                  min: 1,
                  max: 100,
                  divisions: 99,
                  label: _radiusInKm.toStringAsFixed(1),
                  onChanged: (value) => _geoQueryCondition.add(
                    _GeoQueryCondition(
                      radiusInKm: value,
                      cameraPosition: _cameraPosition,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => showDialog<void>(
          context: context,
          builder: (context) => const AddLocationDialog(),
        ),
        child: const Icon(Icons.add),
      ),
    );
  }
} 

main.dart

import 'firebase_options.dart';
import 'package:flutter/material.dart';
import 'bottom_nav_bar/bottom_nav_bar.dart';
import 'package:firebase_core/firebase_core.dart';
//import 'package:flutter/foundation.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: ".env");
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Trotti Park',
      theme: ThemeData(
        primarySwatch: Colors.indigo,
      ),
      home: const MyBottomNavBar(),
    );
  }
}

OrderBy not working

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.

One time query as Future

Hi,
I saw a post that you can use fetchWithin method to fetch geo locations as Future.
When my app starts I would like to query initially Firestore for objects in a certain distance. But only once and not as a stream. Is there an example?
Thanks

Version incompatibility

I need to update the components of my application but the error below is occurring. Do you have any predictions on when it will be compatible?

Resolving dependencies...
Because geoflutterfire_plus >=0.0.21 depends on cloud_firestore ^4.17.0 and dochealth_core depends on cloud_firestore ^5.0.1, geoflutterfire_plus >=0.0.21 is forbidden.
So, because dochealth_core depends on geoflutterfire_plus ^0.0.21, version solving failed.

queryBuilder ใฎ orderBy ใŒๆฉŸ่ƒฝใ—ใชใ„

ใŠ็–ฒใ‚Œๆง˜ใงใ™๏ผ

cloud firestore ใฎ่ค‡ๅˆใ‚ฏใ‚จใƒชใŒ่ค‡ๆ•ฐใฎใƒ•ใ‚ฃใƒผใƒซใƒ‰ๅฏพๅฟœใ—ใฆ่‡ช็”ฑๅบฆ้ซ˜ใใชใฃใŸใฎใง
orderBy ใ‚‚่ฟฝๅŠ ใงๅ…ฅใ‚Œใ‚‰ใ‚Œใ‚‹ใจๆ€ใฃใŸใฎใงใ™ใŒใ€็ขบ่ชใ—ใฆใ„ใŸใ ใ„ใฆ
ใงใใใ†ใงใ—ใŸใ‚‰ๅฏพๅฟœใ—ใฆใ‚‚ใ‚‰ใˆใ‚‹ใจๅฌ‰ใ—ใ„ใงใ™mm

่ค‡ๆ•ฐใƒ•ใ‚ฃใƒผใƒซใƒ‰ใซๅฏพๅฟœใ—ใŸ่ค‡ๅˆใ‚ฏใ‚จใƒชใฎใ‚ขใƒƒใƒ—ใƒ‡ใƒผใƒˆ่ฉณ็ดฐ

https://firebase.google.com/docs/firestore/query-data/multiple-range-fields

[Error report not reproducible] filters support a maximum of 30 elements in the value [Iterable].

I am not using any firestore query along with the fetchWithin function still getting below error.

'package:cloud_firestore/src/query.dart': Failed assertion: line 741 pos 11: '(operator != 'in' && operator != 'array-contains-any') ||
I/flutter (15285): (value as Iterable).length <= 30': 'in' filters support a maximum of 30 elements in the value [Iterable].

My code:-

Future<void> findNearbyLocations() async {
    Future.delayed(Duration.zero);

    try {
      // Query for "Akota Garden" location
      QuerySnapshot querySnapshot = await fireStore
          .collection('locations')
          .where('place_name', isEqualTo: 'Akota Garden')
          .get();

      // Get the first document from the query result
      DocumentSnapshot documentSnapshot = querySnapshot.docs.first;

      // Get the coordinates of "Akota Garden"
      GeoPoint akotaGardenLocation = documentSnapshot['coordinates'];

      // Create a GeoFirePoint for "Akota Garden"
      GeoFirePoint center = GeoFirePoint(akotaGardenLocation);

      // Reference to locations collection.
      final CollectionReference<Map<String, dynamic>> locationCollectionRef =
          fireStore.collection('locations');

      final result =
          await GeoCollectionReference(locationCollectionRef).fetchWithin(
        center: center,
        radiusInKm: 6,
        field: 'geo',
        strictMode: true,
        geopointFrom: geopointFrom,
      );

      for (var value in result) {
        String placeName = value['place_name'];
        final distance =
            center.distanceBetweenInKm(geopoint: value['coordinates']);

        print(placeName);
        print("Distance : $distance");
      }
    } catch (e) {
      print("ERROR IN LOCATION : $e");
    }
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.