Reputation: 15
I am trying to achieve Multi Filter Feature like that In Zillow App. I am using Flutter, Firebase, and Provider Package.
Users can filter by Price Range, Area Range, City, Zipcode, Bathrooms, Bedrooms, and Amenities. Users can select any combination of filters. When calculating it using combinations, I ended up with 127 combinations?
Future<void> getApartmentbyCityPrice(PersonalHomeList personalApartmentList,String city,double
maxPrice, double minPrice) async {
if (city == "Any" && maxPrice != null && minPrice != null) {
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').
where("price",isGreaterThanOrEqualTo: minPrice, isLessThanOrEqualTo: maxPrice).get();
List<PersonalApartment> _loadedPersonalApartment = [];
snapshot.docChanges.forEach((result) {
PersonalApartment personalApartment = new PersonalApartment(
id: result.doc['id'],
userId: result.doc['userId'],
amenities: result.doc['amenities'],
area: result.doc['area'],
bathroom: result.doc['bathroom'],
bedroom: result.doc['bedroom'],
city: result.doc['city'],
createdAt: result.doc['createdAt'],
description: result.doc['description'],
imageUrl: result.doc['imageUrl'],
price: result.doc['price'],
streetName: result.doc['streetName'],
updatedAt: result.doc['updatedAt'],
zipcode: result.doc['zipcode'],
);
_loadedPersonalApartment.add(personalApartment);
});
personalApartmentList.apartmentListByCity = _loadedPersonalApartment;
} else if (city.isNotEmpty && city != "Any" && maxPrice == 0.0 && minPrice == 0.0) {
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments')
.where("city", isEqualTo: city).get();
List<PersonalApartment> _loadedPersonalApartment = [];
snapshot.docChanges.forEach((result) {
PersonalApartment personalApartment = new PersonalApartment(
id: result.doc['id'],
userId: result.doc['userId'],
amenities: result.doc['amenities'],
area: result.doc['area'],
bathroom: result.doc['bathroom'],
bedroom: result.doc['bedroom'],
city: result.doc['city'],
createdAt: result.doc['createdAt'],
description: result.doc['description'],
imageUrl: result.doc['imageUrl'],
price: result.doc['price'],
streetName: result.doc['streetName'],
updatedAt: result.doc['updatedAt'],
zipcode: result.doc['zipcode'],
);
_loadedPersonalApartment.add(personalApartment);
});
personalApartmentList.apartmentListByCity = _loadedPersonalApartment;
} else {
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').where("city",
isEqualTo: city).where("price",isGreaterThanOrEqualTo: minPrice, isLessThanOrEqualTo: maxPrice)
.get();
List<PersonalApartment> _loadedPersonalApartment = [];
snapshot.docChanges.forEach((result) {
PersonalApartment personalApartment = new PersonalApartment(
id: result.doc['id'],
userId: result.doc['userId'],
amenities: result.doc['amenities'],
area: result.doc['area'],
bathroom: result.doc['bathroom'],
bedroom: result.doc['bedroom'],
city: result.doc['city'],
createdAt: result.doc['createdAt'],
description: result.doc['description'],
imageUrl: result.doc['imageUrl'],
price: result.doc['price'],
streetName: result.doc['streetName'],
updatedAt: result.doc['updatedAt'],
zipcode: result.doc['zipcode'],
);
_loadedPersonalApartment.add(personalApartment);
});
personalApartmentList.apartmentListByCity = _loadedPersonalApartment;
}
}
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').where("price",
isGreaterThanOrEqualTo: minPrice, isLessThanOrEqualTo: maxPrice).get();
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').where("area",
isGreaterThanOrEqualTo: areaRange.start, isLessThanOrEqualTo: areaRange.end).get();
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').
where("bathroom", arrayContainsAny: bathroom).get();
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('apartments').where("bedroom",
arrayContainsAny: bedroom).get();
[![Filter Screen] [![Filter Screen
]
Upvotes: 0
Views: 492
Reputation: 8383
I suppose you are using Firestore.
Now, you want to query Firestore for apartments based on:
What you want to do is to use Compound Queries:
Query query = FirebaseFirestore.instance.collection('apartments');
if (city.isNotEmpty && city != "Any") {
query = query.where("city", isEqualTo: city)
}
if (zipCode.isNotEmpty && zipCode != "Any") {
query = query.where("zipCode", isEqualTo: zipCode)
}
...
QuerySnapshot snapshot = await query.get();
List<PersonalApartment> apartments = snapshot.docChanges.map(
(result) => PersonalApartment.fromFirestore(result.doc),
);
Your main problem will be that Compound Queries are very limited in Firestore. One of the limitations is that you cannot combine range filters on multiple fields.
So, you can only perform one range filter in your query and the other client-side within your application. Maybe you could determine an order on the range filters from the most restrictive (the one that will return the smallest set of apartments) to the most general.
Query _buildQuery() {
Query query = FirebaseFirestore.instance.collection('apartments');
// SIMPLE QUERIES
if (city.isNotEmpty && city != "Any") {
query = query.where("city", isEqualTo: city)
}
if (zipCode.isNotEmpty && zipCode != "Any") {
query = query.where("zipCode", isEqualTo: zipCode)
}
// RANGE QUERIES
if (minPrice != null || maxPrice != null) {
if (minPrice != null) {
query = query.where("price", ">=", minPrice);
}
if (maxPrice != null) {
query = query.where("price", "<=", maxPrice);
}
return query;
}
if (minArea != null || maxArea != null) {
...
return query;
}
if (...) { ... }
...
return query;
}
...
QuerySnapshot snapshot = await _buildQuery().get();
List<PersonalApartment> apartments = snapshot.docChanges.map(
(result) => PersonalApartment.fromFirestore(result.doc),
);
apartments = apartments.where((apartment) { /* perform remaining filters clmient-side */ })
Upvotes: 2