Complex Firebase query with geofire - flutter

Query<Map<String, dynamic>> collectionReference
Type: Query<Map<String, dynamic>>
The argument type 'Query<Map<String, dynamic>>' can't be assigned to the parameter type 'CollectionReference<Object?>'.
We are trying to query our task collection and filter it based on topic, status, userid but we are getting the above error.
We are using the Geofire lib along with Firebase
Future<void> fetchTasksNearBy(double lat, double lng) async {
print('getting tasks in location');
GeoFirePoint center = geo.point(latitude: lat, longitude: lng);
double radius = 60; //in km
String field = 'location';
// Reading nearby tasks based on lat, lng parameters
try {
var collectionReference = tasksRef
.where('status', isEqualTo: 'Posted')
.where('ownerId', isNotEqualTo: widget.user!.id)
.where('category.subCategoryId', isEqualTo: widget.subCat);
Stream<List<DocumentSnapshot>> placesStream =
geo.collection(collectionRef: collectionReference).within(
center: center,
radius: radius,
field: field,
strictMode: true,
); // = false includes borderline places
await for (var doclist in placesStream) {
if (doclist.isNotEmpty) {
for (DocumentSnapshot ds in doclist) {
print('${ds.id} ${ds['title']}');
}
} else {
print('Nearby tasks do not exist in the database');
}
}
} catch (e) {
print(e);
}
}

Related

How to fetch a `DocumentReference` from a Firebase `get()`

I have a collection ads that contains a DocumentReference as ownerId.
With the code below, I am able to fetch the 10 most recent ads as aList<Ad>:
/// Returns a list of ads of the given [category]
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
return FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get()
.then((snapshot) {
return snapshot.docs.map((doc) {
final data = doc.data();
return Ad.fromMap(data);
}).toList();
});
But now I'd like to fetch the owner (collection users) from the DocumentReference I was talking about above. But I am a but puzzled about how to do that.
My modified code below does not compile:
The return type 'List' isn't a 'FutureOr<List>', as required by the closure's context.
/// Returns a list of ads of the given [category]
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
return FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get()
.then((snapshot) {
// <<<< Error starts right here down to the removeWhere()
return snapshot.docs.map((doc) {
final data = doc.data();
final DocumentReference docRef = data["ownerId"];
return docRef.get().<ClassifiedAd?>then((snapshot) {
if (snapshot.exists) {
return ClassifiedAd.fromMap(data);
}
return null;
});
}).toList()
// Don't take into account potential nulls
..removeWhere((a) => a == null);
});
How should I do that?
I would say that the wrong thing that you're doing is you're trying to get a snapshot asynchronously inside the map() method which is synchronous, for such cases like yours, I recommend using await/async and to not return anything until you guarantee that you got it, try this:
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
final snapshot = await FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get();
List<ClassifiedAd> result = [];
for (int index = 0; index < snapshot.docs.length; index++) {
final doc = snapshot.docs[index];
final data = doc.data();
final DocumentReference docRef = data["ownerId"];
final docOwnerSnapshot = await docRef.get();
if (docOwnerSnapshot.exists) {
result.add(ClassifiedAd.fromMap(data));
}
}
return result;
}

Geoflutterfire with where condition `isGreaterThan` not working

I am trying to query time with condition isGreaterThan, but it doesn't show data.
The code is correct, but I don't know problem.
I want to show data time isGreater selected time.
I think to there is problem in Geoflutterfire with condition isGreaterThan.
_setStream() async {
_locationData = await location.getLocation();
var pos = await location.getLocation();
double lat = pos.latitude!;
double lng = pos.longitude!;
print('timeeeeeeeee$_time');
int _ti = Timestamp.now().millisecondsSinceEpoch - 999 * 60 * widget.time;
var ref = await FirebaseFirestore.instance
.collection('now')
.where('gender', isEqualTo: widget.gender)
.where('time', isGreaterThan: _ti)
.orderBy('time', descending: true);
GeoFirePoint center = geo.point(latitude: lat, longitude: lng);
stream = radius.switchMap((rad) {
var collectionReference = ref;
return geo.collection(collectionRef: collectionReference).within(
center: center, radius: rad, field: 'location', strictMode: true);
});
setState(() {
isLoading = false;
});
stream = geo.collection(collectionRef: ref).within(
center: center,
radius: widget.distance,
field: 'location',
strictMode: true);
stream!.listen((List<DocumentSnapshot> documentList) {
documentList.forEach((element) {
print("from data .......element");
print(element.data());
final data = element.data() as Map<String, dynamic>;
final GeoPoint point = data['location']['geopoint'];
print("from data .......latitude");
print(point.latitude);
});
});
}
Firestore queries can only perform range conditions (>= and such) on a single field. When you use GeoFire, it already needs to perform this condition on the geohash value to perform the geoquery, so you can't perform a range condition on any other field.
If you want to understand why that is, I recommend watching this video on implementing geoqueries on Firebase's NoSQL databases.
If also recommend checking this answer I gave recently on adding an additional range filter to a geoquery, which covers common workarounds: Is it possible to query Firebase Firestore by both a location and age range?

Query with condition isNotEqualTo not work in flutter

I have a problem with the query with the condition isNotEqualTo does not work and does not show the values ​​checked from the condition, note that I tried the condition isNotEqualTo and it worked
What is the problem
_setStream() async {
var pos = await location.getLocation();
double lat = pos.latitude!;
double lng = pos.longitude!;
var ref = await FirebaseFirestore.instance.collection('now')
.where('uid', isNotEqualTo: _user.uid).orderBy('uid');
GeoFirePoint center = geo.point(latitude: lat, longitude: lng);
stream = radius.switchMap((rad) {
var collectionReference = ref;
return geo.collection(collectionRef: collectionReference).within(
center: center, radius: rad, field: 'location', strictMode: true);
});
setState(() {
isLoading = false;
});
stream = geo.collection(collectionRef: ref).within(
center: center, radius: 2000, field: 'location', strictMode: true);
stream!.listen((List<DocumentSnapshot> documentList) {
documentList.forEach((element) {
print("from data .......element");
print(element.data());
final data = element.data() as Map<String, dynamic>;
final GeoPoint point = data['location']['geopoint'];
print("from data .......latitude");
print(point.latitude);
});
});
}
Even though NotEqual query is available in firebase, it was made available late in flutter plugin. The best option is to fetch all to a list and remove unwanted elements from the list

geoflutterfire stream to Future

I have to query the geoflutterfire data with a Stream.
But I would like to use this in a Future in a ChangeNotifierprovider to be able to wait until the Stream has all data.
I never built a Future with a Stream in it before. What do I have to return?
When I don't have a return and just do notifyListeners(), the function runs forever. So I just put in return true.
Is there a better way to do this?
Future<void> fetchPlacesNearBy(double lat, double lng) async {
print("GETTING FIRESTORE PLACES");
GeoFirePoint center = geo.point(latitude: lat, longitude: lng);
double radius = 5; //in km
String field = 'geo_location';
// Reading nearby places based on lat, lng parameters
try {
Stream<List<DocumentSnapshot>> placesStream =
geo.collection(collectionRef: _placesRef).within(
center: center,
radius: radius,
field: field,
strictMode: false,
); // = false includes borderline places
await for (var doclist in placesStream) {
topWikiPlacesAroundUser2 = [];
if (doclist.length > 0) {
for (DocumentSnapshot ds in doclist) {
/// Init place model
WunderkPlace pl = WunderkPlace.fromMap(
ds.data(), ds.get('geo_location.geopoint'));
topWikiPlacesAroundUser2.add(pl);
}
} else {
print('Nearby places do not exist in the database');
}
notifyListeners();
return true;
}
} catch (e) {
print(e);
return false;
}
}

I can't get result of Future

I have this initState:
#override
void initState() {
super.initState();
_initState();
}
_initState() async {
_geIdsList().then((result) {
_idList = result;
print('result $_idList');
}, onError: (e) {
print('error $e');
});
}
Then there's my function to fetch the IDs from Firestore:
Future<List<String>> _geIdsList() async {
List<String> ids = [];
StreamSubscription stream;
Firestore _firestore = Firestore.instance;
Geoflutterfire geo;
var collectionReference = _firestore.collection('locations');
geo = Geoflutterfire();
var location = new Location();
var pos = await location.getLocation();
var radius = BehaviorSubject<double>.seeded(10.0);
GeoFirePoint center = geo.point(latitude: pos.latitude.toDouble(), longitude: pos.longitude.toDouble());
stream = radius.switchMap((rad) {
return geo.collection(collectionRef: collectionReference).within(
center: center, radius: rad, field: 'position', strictMode: true);
}).listen((List<DocumentSnapshot> documentList) {
Future.forEach(documentList, (DocumentSnapshot documentSnapshot) {
print('document here ... $documentSnapshot' );
print(documentSnapshot.data['id']);
var id = documentSnapshot.data['id'].toString();
ids.add(id);
}).whenComplete(() {
stream.cancel();
print('ids from function $ids');
return ids;
});
});
}
Now _getIdsList() is working fine and the
when complete print('ids from function $ids');
line, prints the IDs List and I'm unable to understand why it doesn't work in my initState. Can anyone tell me what's wrong with my code?