Flutter how to get province and cities? - flutter

I am searching for plugin from which I can get province and cities for one country only. Mean I dont want to select country.
I have found this plugin which is good but issue is its asking for country pick.
https://pub.dev/packages/restcountries

From the examples at this link
List cities = await api.getCities(
countryCode: 'id', region: 'Jawa Timur', keyword: 'mal');
Since you already know which country you want to get the cities from, just assign that country's code to countryCode,
For example, if you want cities of United States with keyword ar,
List<City> cities = await api.getCities(
countryCode: 'us', keyword: 'ar');

I have to agree with the above answer. Given a County you could make a series of calls to get the data set you want.
countries = await api.getCountries(); -- Will return the countries the service has, then search through the list to find the one you want.
regions = await api.getRegions(countryCode: 'id'); -- Will then get you the regions for the country, I'm assuming you'll get the code from the first call, otherwise a good place to start with the code would be to use the the IEEE country codes.
Check Them Out Here
Finally use the regions you got to get the cities;
await api.getCities(countryCode: 'id', region: 'Jawa Timur');
Bringing it all together you'd have something like this... (I have not looked at the API specification so the guess at a memeber in that loop "region.name" is likely incorrect)
import 'package:restcountries/restcountries.dart';
void main() async {
var api = RestCountries.setup(Platform.environment['API_KEY']);
List<Country> countries;
List<Region> regions;
List<City> cities;
countries = await api.getCountries();
// Search here for your country
regions = await api.getRegions(countryCode: '*YOUR COUNTRY CODE HERE*');
// Now we loop to get cities in every region.
regions.forEach((region){
cities += await api.getCities(countryCode: '*YOUR COUNTRY CODE HERE*', region: region.name);
});
print(regions);
print(cities);
}

Related

How to make a WishedProduct Widget using FirebaseFirestore

I'm making a product display app.
I'm going to create a "Wish List" widget that brings up the product that the user picked as 'wish item'.
I structured it as shown in picture 1.
And to create a widget,
I get all the documents of the collection('wish') of doc('User A').
And with their String values(product name) of the doc,
Get the product data from the collection ('Product') using Query.
The product collection is shown in the picture below.
Is there a more efficient way?
I thought it might be easier to change the data structure.
However, even if I create a new Collection('Wish'), at the same level as Collection('Product'), and put the product's name and user's e-mail in it,
I need to focus on the 'Product' collection with the 'Product name'.
Because I have to use the price, brand, name of product, in Collection('Product').
Is there any other efficient way I'm missing? Thank you!
Instead of storing the product name in string you can use reference type to store direct reference of the document inside other document.
Example code
DocumentReference ref = db.collection('products').doc('product-document-id');
Map<String,dynamic> data = {
'name' : 'Product A',
'product_ref' : ref, // Product document Reference
};
db.collection("users")
.doc("user-id")
.collection("wish")
.doc("your_product_name")
.set(data);
This will add the wish product with dynamic id.
Now you can directly read the document using the product_ref. You can use something like this
final docRef = db.collection("users")
.doc("user-id")
.collection("wish").doc("your_product_name");
final docSnapshot = await docRef.get();
if (docSnapshot.exists) {
final data = doc.data() as Map<String, dynamic>;
var productRef = data?['product_ref'];
productRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
// you will get your product here
}
});
}

How to show list in flutter whose id matches

I have two list of data stored in
1. final profiles = context.watch<ProfilesBloc>().state.profiles;
2. final users= context.watch<UsersBloc>().state.users;
I want to build the list with the only whose profile.id matches the user.id
I tried by if (user.id == profiles.id) but it's not working
any help?
var newUser = users.where((user) => user.id.toLowerCase().contains(profiles.id.toLowerCase()).toList();
you can basically use this method to check a condition to create a new list. Feel free to alter the codes as per your requirements.

Dart streams (Flutterfire): Should I use the where filter before or after mapping?

I'm making an app using Flutter, with Cloud Firestore for the backend. I have a stream which retrieves a list of user documents for all users and want to filter the users whose favorite food is "pasta". I don't want to load the other documents. Here is my stream, and the function which maps it to my user model.
final CollectionReference usersCollection =
FirebaseFirestore.instance.collection('Users');``
List<MyAppUser> _userListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((DocumentSnapshot doc) {
return MyAppUser(
uid: doc.id ?? '',
name: (doc['name']).toString() ?? '',
email: (doc['email']).toString() ?? '',
favorite_food: (doc['favorite food']).toString() ?? '',
);
}).toList();
}
Stream<List<MyAppUser>> get users {
return usersCollection.snapshots().map(_userListFromSnapshot);
}
Here is my user model if needed:
class MyAppUser{
final String uid;
final String name;
final String email;
final String favorite_food;
MyAppUser({
this.name,
this.email,
this.uid,
this.favorite_food,
});
}
Should I use a where function after mapping or before?
If I filter before mapping, I will have to do a where on the original stream like
usersCollection.where('favorite food', isEqualTo: 'pasta')
If I filter after mapping, I can get type safety:
I listen to the stream with Provider: final users = Provider.of<List<MyAppUser>>(context);
Then query like this:
users.where((user) => user.favorite_food == 'pasta');
I would prefer to use typesafety, but, will I be billed for reading only the filtered documents or all documents?
I got this answer from Aurimas Deimantas, after commenting on their article on medium.com. Below, I have adapted their answer to suit this question.
Firestore bills you based on how many document reads you have.
It will be better to filter before mapping, with
usersCollection.where('favorite food', isEqualTo: 'pasta')
because this will only read the documents where favorite food is pasta.
If you filter after mapping, like this:
users.where((user) => user.favorite_food == 'pasta');
then all user documents will be read, and after that, filtered. So Firestore will bill you for all the document reads instead of only those whose favorite food is pasta.
This is why it saves money to filter on the userscollection directly, before mapping it to your model.
If you want to map the stream to your model, you can do it after the where filter, by adding the .map(...) function after the .where(...) function, and this will map (& read) only the documents that pass the where filter, saving money.
You can use where clause just after collection calling like
... Collection('Users').where(field, conditions)
With this, you don't have filter list using collection

How to approach dynamically generated Firestore queries depending on nested user created Sub Collections?

/Countries/Lebanon/Governorates/Mount Lebanon/Districts/Chouf/Cities/Wadi al-Zayneh/Data/Products/Main Categories/Restaurants & Bakeries/Sub Categories/Snack/Sub Categories/Abo Arab Cafe
So as you can see, this is a snippet from my current Firestore structure. So many deeply nested collections. The issue is, I want to keep going deeper as long as a collection called 'Sub Categories' is found which in that case I would render them in the UI. And when eventually I reach a level where 'Sub Categories' is not found, I will render a different UI and show the actual products (The last document "Abo Arab Cafe" contains all the products as maps). The pattern of how many Sub Categories there are is unexpectable and can be modified by the end user.
How can I keep checking for Sub Categories? How to manage my queries in a way that they are dynamically generated at each level at the client-side?
I use Flutter. Here is my current queries structure:
import 'package:cloud_firestore/cloud_firestore.dart';
class FirebaseServices {
final FirebaseFirestore _db = FirebaseFirestore.instance;
CollectionReference mainCategoryCollectionReference() {
CollectionReference mainCategoryCollectionReference = _db.collection(
'/Countries/Lebanon/Governorates/Mount Lebanon/Districts/Chouf/Cities/Wadi al-Zayneh/Data/Products/Main Categories');
return mainCategoryCollectionReference;
}
CollectionReference subCategoryCollectionReference(
String parentSelectedCategory) {
CollectionReference mainCategoryCollectionReference = _db.collection(
'/Countries/Lebanon/Governorates/Mount Lebanon/Districts/Chouf/Cities/Wadi al-Zayneh/Data/Products/Main Categories/$parentSelectedCategory/Sub Categories');
return mainCategoryCollectionReference;
}
bool checkIfSubCategoriesExist(CollectionReference collectionReference) {
bool subCategoriesExist;
collectionReference.get().then((value) => {
subCategoriesExist = value.docs.isNotEmpty,
print('SubCategoriesExist: $subCategoriesExist')
});
return subCategoriesExist;
}
}
This works only if I know for certain how many levels of deepness there are, but since this can be modified by the user, it won't work.
Sorry for the very long question I had no idea how to explain it properly and clearly. Thank you in advance!
The structure is all wrong, there is no point in the structure being this deeply nested. The structure of the database needs to match what has to appear in the UI.
Assuming this is a worldwide application since you are using countries then you have to do the following:
Collection
Document
Fields
Countries
Random ID
countryName - arrayOfDistrict- arrayOfGovernorates
3 Fields under each document id, containing information about the country.
Then regarding Resturants:
Collection
Document
Fields
SubCollection
subCollectionId
Fields
Resturant
Random ID
resturant_name- resturant_location - info_about_resturant
Menu
randomId
dish_name - price -...
The problem with your db structure is that it is very nested instead of making a flat structure and that right now you are harcoding the whole path.
Using the above structure, you can create a dropdown with list of countries if the user chooses Lebanon, then you get the districts and the governorates. Then you can do a call to get the resturants that are inside each district, since in the documents inside Resturant collection you can get location of each resturant and name.
After that on click of each resturant, you will get the data inside the subcollection that will contain the full menu.
I think I found the solution with the help of a friend!
Since the checkIfSubCategoriesExist function is always checking on the very last reached level(using the collectionReference argument) whether Sub Categories exists or not, he suggested that in case it does exist, I can append to its argument collectionReference the new "Sub Categories" String to the path as a variable! This way I can query on it and voila!

CS0266 Cannot implicitly convert type 'System.Collections.Generic.List<System.Linq.IGrouping to 'System.Collections.Generic.List'

I am using Entity Framework 7 Code First
I have a function that needs to returns a list of Countries(ids,Names) linked to a User.
The User isn't directly linked to the Country but is linked via the City. City is linked to State. State is linked to Country.
I decided to use a GroupBy to get the list of countries.
public async Task<IEnumerable<Country>> Search(int userId)
{
var table = await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.ToListAsync()
;
return table;
}
However I get the error:
CS0266 Cannot implicitly convert type
'System.Collections.Generic.List <System.Linq.IGrouping> to
'System.Collections.Generic.List'
How do I return a variable IEnumerable<Country> as that is what the receiving code expects i.e. a list of Countries?
Am I doing my grouping correct?
For performance I assume grouping is better than a distinct or a contains
If you want to have the distinct countries, you can use a select afterwards to select the first country in each IGrouping<int,Country>:
public async Task<IEnumerable<Country>> Search(int userId)
{
return await _db.Cities
.Include(ci => ci.States.Country)
.Select(ci => ci.States.Country)
.OrderBy(co => co.CountryName)
.GroupBy(co=>co.pk_CountryId)
.Select(co => co.FirstOrDefault())
.ToListAsync();
}
Also a little sidenote, the Include isn't necessary here, eager loading the countries would only be useful if you were to return the States and wanted its Country property be populated. The Select makes sure you're grabbing the Country, you're not even fetching the states anymore from database.