Reputation: 191
I have a complex query to perform. I have added a composite index for this query in my Firebase project. This is the query.
FirebaseFirestore.instance
.collection('HouseDetails')
.where('housePrice', isGreaterThan: GV.price[0].ceil() - 1)
.where('housePrice', isLessThan: GV.price[1].ceil() + 1)
.where('houseArea', isGreaterThan: GV.area[0].ceil() - 1)
.where('houseArea', isLessThan: GV.area[1].ceil() + 1)
.where('bathrooms',
isEqualTo: int.parse(bathrooms.first).ceil() + 1)
.snapshots();
which throws an error
I/flutter ( 9116): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 9116): The following assertion was thrown while handling a gesture:
I/flutter ( 9116): All where filters with an inequality (<, <=, >, or >=) must be on the same field. But you have
I/flutter ( 9116): inequality filters on 'FieldPath([housePrice])' and 'FieldPath([houseArea])'.
I/flutter ( 9116): 'package:cloud_firestore/src/query.dart':
I/flutter ( 9116): Failed assertion: line 484 pos 18: 'hasInequality == field'
After reading the documentation I understood that I cannot filter out multiple field types at once. But I did not understand how to perform the queries which needs more than one field for comparison (housePrice
and houseArea
in my case).
How Do I perform these queries?
Upvotes: 1
Views: 396
Reputation: 5608
I know it's annoying (I've been there), but Firestore doesn't allow where filters with inequality on different fields as is stated in the documentation:
You have two workarounds:
housePrice
along with bathrooms
in server side and houseArea
in client side:FirebaseFirestore.instance
.collection('houseDetails')
.where('housePrice', isGreaterThan: GV.price[0].ceil() - 1)
.where('housePrice', isLessThan: GV.price[1].ceil() + 1)
.where('bathrooms', isEqualTo: int.parse(bathrooms.first).ceil() + 1)
.snapshots()
// Transform each query snapshot into new stream as list of document snapshots
.map<List<QueryDocumentSnapshot<Map<String, dynamic>>>>(
// Discard any document snapshots whose house area data is not in the range
(querySnapshot) => querySnapshot.docs.where((snapshot) {
// Try to parse house area as number
// Note: I don't know house area is a double or int, so I used num for type safety
final houseArea = num.tryParse(snapshot.data()["houseArea"]);
// Make sure house area is not null
if (houseArea != null) {
// and make sure house area is in the range you specified
if (houseArea > GV.area[0].ceil() - 1) {
if (houseArea < GV.area[1].ceil() + 1) {
// Return true to add the document snapshot to list
return true;
}
}
}
// Return false to discard the document snapshot
return false;
}).toList(),
);
houseDetails-200k-350k
, and perform filtering on houseArea
and bathrooms
:FirebaseFirestore.instance
.collection('houseDetails-200k-350k')
.where('houseArea', isGreaterThan: GV.area[0].ceil() - 1)
.where('houseArea', isLessThan: GV.area[1].ceil() + 1)
.where('bathrooms', isEqualTo: int.parse(bathrooms.first).ceil() + 1)
.snapshots();
Upvotes: 1
Reputation: 786
You have to choose one field, and then from the result, you can filter another fields.
For example,
ModelHouseDetails _requestHouseDetailsFromSnapshot(DocumentSnapshot snapshot) {
return ModelHouseDetails(
houseId: snapshot.id,
houseArea: snapshot['houseArea'],
housePrice: snapshot['housePrice'],
bathrooms: snapshot['bathrooms']);
}
Stream<List<HouseDetails>> get listHouseDetails {
return FirebaseFirestore.instance.collection('request-service')
.where('housePrice', isGreaterThan: GV.price[0].ceil() - 1)
.where('housePrice', isLessThan: GV.price[1].ceil() + 1)
.snapshots()
.map((snapshot) =>
snapshot.docs.where((element) => element['houseArea'] >= GV.area[0].ceil() - 1 && element['houseArea'] <= GV.area[1].ceil() + 1 && element['bathrooms'] == int.parse(bathrooms.first).ceil() + 1).map(_requestHouseDetailsFromSnapshot).toList());
}
Upvotes: 0