geoflutterfire_plus permet à vos applications flutter d’interroger les données géographiques enregistrées dans Cloud Firestore.
Ce paquet est une fourche de GéoFlutterFireet a essayé d’être constamment maintenu pour fonctionner avec les derniers SDK Flutter, Dart SDK et d’autres packages de dépendance.
Conditions préalables
Dart: '>=2.17.0 <3.0.0'
Flutter: '>=2.10.0'
Installation
Exécutez cette commande :
flutter pub add geoflutterfire_plus
Ou ajoutez une dépendance à votre pubspec.yaml
.
dependencies:
geoflutterfire_plus: <latest-version>
Requêtes géographiques
Reportez-vous au document officiel de Firebase Requêtes géographiques pour comprendre ce qu’est Geohash, pourquoi vous devez enregistrer la géolocalisation en tant que Geohash et comment les interroger. Cela vous aidera également à comprendre les limites de l’utilisation de Geohashes pour interroger des emplacements.
Enregistrer les données géographiques
Pour enregistrer les données géographiques en tant que documents de Cloud Firestore, utilisez GeoFirePoint
. GeoFirePoint.data
donne géopoint (GeoPoint
type défini dans cloud_firestore
package) et la chaîne Geohash.
// Define GeoFirePoint instance by giving latitude and longitude.
final GeoFirePoint geoFirePoint = GeoFirePoint(35.681236, 139.767125);
// Get 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
l’instance fournit add
méthode pour créer un nouveau document dans la collection (en interne, en appelant simplement add
méthode de cloud_firestore
).
// Add new documents to locations collection.
GeoCollectionReference<Map<String, dynamic>>(
FirebaseFirestore.instance.collection('locations'),
).add(<String, dynamic>{
'geo': geoFirePoint.data,
'name': name,
'isVisible': true,
});
Ou, vous pouvez simplement appeler add
ou alors set
méthode de cloud_firestore
pour sauvegarder les données. Par exemple,
// Add new documents to locations collection.
FirebaseFirestore.instance.collection('locations').add(
<String, dynamic>{
'geo': data,
'name': 'Tokyo Station',
'isVisible': true,
},
);
Le document créé ressemblerait à la capture d’écran ci-dessous. Chaîne de géohachage (geohash
) et données Cloud Firestore GeoPoint (geopoint
) est enregistré dans geo
champ comme type de carte.
Afin de définir ou de mettre à jour la paire de latitude et de longitude comme cloud_firestore
Chaîne GeoPoint et Geohash sur le champ donné du document spécifié, GeoCollectionReference.setPoint
est disponible.
// Set or update geo field on the specified document.
GeoCollectionReference(FirebaseFirestore.instance.collection('locations'))
.setPoint(
id: 'your-document-id',
field: 'geo',
latitude: 35.681236,
longitude: 139.767125,
);
Interroger les données géographiques
Afin d’interroger des documents de localisation dans un rayon de 50 km autour de la gare de Tokyo, vous allez écrire une requête comme celle-ci :
Requête de base
// Center of the geo query.
final GeoFirePoint center = GeoFirePoint(35.681236, 139.767125);
// 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).within(
center: center,
radiusInKm: radiusInKm,
field: field,
geopointFrom: geopointFrom,
);
En utilisant withConverter
Si vous souhaitez utiliser withConverter
pour écrire une requête en toute sécurité, vous devez d’abord définir sa classe d’entité et ses constructeurs d’usine.
/// 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,
};
}
Ensuite, définissez la référence de collection typée.
/// Reference to the collection where the location data is stored.
final typedCollectionReference =
FirebaseFirestore.instance.collection('locations').withConverter(
fromFirestore: (ds, _) => Location.fromDocumentSnapshot(ds),
toFirestore: (obj, _) => obj.toJson(),
);
// Function to get GeoPoint instance from Location instance.
GeoPoint geopointFrom: (Location location) => location.geo.geopoint;
Vous pouvez écrire une requête de la même manière que dans le premier exemple.
// Streamed document snapshots of geo query under given conditions.
final Stream<List<DocumentSnapshot<Location>>> stream =
GeoCollectionReference<Location>(typedCollectionReference).within(
center: center,
radiusInKm: radiusInKm,
field: field,
geopointFrom: geopointFrom,
);
Conditions de requête personnalisées
Si vous souhaitez ajouter des conditions de requête personnalisées, queryBuilder
paramètre de within
méthode est disponible.
Par exemple, lorsque vous filtrez uniquement isVisible
champ est true
documents, votre queryBuilder
serait comme ça :
// Custom query condition.
Query<Location> queryBuilder(Query<Location> query) =>
query.where('isVisible', isNotEqualTo: true);
Ensuite, il suffit de donner le queryBuilder
au paramètre de within
méthode.
🚨 Remarque : La condition de requête personnalisée peut nécessiter un index composite. Si l’index n’est pas créé, vous verrez le « [cloud_firestore/failed-precondition] La requête nécessite un index… » erreur de Firestore sur la console de débogage. Vous pouvez créer l’index en cliquant sur le lien dans le message d’erreur.
// Streamed document snapshots of geo query under given conditions.
final Stream<List<DocumentSnapshot<Map<String, dynamic>>>> stream =
GeoCollectionReference<Map<String, dynamic>>(typedCollectionReference).within(
center: center,
radiusInKm: radiusInKm,
field: field,
geopointFrom: geopointFrom,
queryBuilder: queryBuilder,
);
GitHub
Voir Github