Flutter firestore remove ignore doc - flutter

What I need to do is I have a list of ids and I need to fetch data from firestore and ignore those id which are available on that data (Those data doc id is same which are in ids)
I am doing like this
getProfiles(BuildContext context) async {
var profileProvider = Provider.of<profilesProvider>(context, listen: false);
final userProviderState = Provider.of<userProvider>(context, listen: false);
final globalProviderState =
Provider.of<globalProvider>(context, listen: false);
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return spinkit;
});
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection(USER_COLLECTION);
QuerySnapshot querySnapshot = await _collectionRef.get();
List allData = querySnapshot.docs.map((doc) => doc.data()).toList();
final likestate = Provider.of<LikeDislikeProvider>(context, listen: false);
for (var i = 0; i < likestate.likedislikePRofiles.length; i++) {
allData.removeWhere(
(item) => item['id'] == likestate.likedislikePRofiles[i].oppositeId);
}
allData.forEach((element) {
GeoPoint point = element['Location'];
if (calculateDistance(
userProviderState.user[0].Latitude,
userProviderState.user[0].Longitude,
point.latitude,
point.longitude)) {
profileProvider.addProfile(element);
} else {}
});
Navigator.pop(context);
}
But in this issue is I am getting all data then by for loop i am removing it which I don't think is good when data is too much. So what I want is from query I can ignore those data which doc id is same as in arrays.
Here is screenshot docid and id in data is same. I have list of doc id which needs to ignore.

Related

How can I load my firestore database data quickly into my flutter application?

I am working on a recipe application on flutter. I have firestore database where my recipes data is stored.
Take a look at the database: .
This is how I am getting data from the database:
#override
void initState() {
super.initState();
getRecipeData();
}
Future<void> getRecipeData() async {
WidgetsBinding.instance.addPostFrameCallback((_) async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
dialogContext = context;
return ProgressBar(
message: "Loading..",
);
},
);
});
int count = await RecipeModel().getRecipeCount();
int recipeID = 101;
for (int i = 0; i < count; i++, recipeID++) {
if (await RecipeModel().checkIfRecipeDocExists(recipeID.toString()) ==
true) {
recipeIDs.add(recipeID.toString());
recipeDescription.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipe_description'))!);
recipeName.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipe_name'))!);
recipeURL.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipeImageURL'))!);
recipeRating.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipe_rating'))!);
recipeTime.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipe_time'))!);
recipeIngredients.add((await RecipeModel()
.getRecipeData(recipeID.toString(), 'recipe_ingredients'))!);
}
}
for (int i = 0; i < recipeIDs.length; i++) {
recipes.add(
Recipes(
recipeID: recipeIDs[i],
recipeName: recipeName[i],
recipeDescription: recipeDescription[i],
recipeIngredients: [recipeIngredients[i]],
recipeRating: recipeRating[i],
recipeTime: recipeTime[i],
recipeURL: recipeURL[i]),
);
}
Navigator.pop(dialogContext!);
}
This is my recipeModel class:
class RecipeModel {
Future<String?> getRecipeData(String recipeID, String key) async {
try {
CollectionReference recipes =
FirebaseFirestore.instance.collection('recipes');
final snapshot = await recipes.doc(recipeID).get();
final data = snapshot.data() as Map<String, dynamic>;
return data[key].toString();
} catch (e) {
return 'Error fetching user';
}
}
Future<int> getRecipeCount() async {
int count = await FirebaseFirestore.instance
.collection('recipes')
.get()
.then((value) => value.size);
return count;
}
Future<bool> checkIfRecipeDocExists(String recipeID) async {
try {
var collectionReference =
FirebaseFirestore.instance.collection('recipes');
var doc = await collectionReference.doc(recipeID).get();
return doc.exists;
} catch (e) {
rethrow;
}
}
}
I don't know Why it take around 10-15seconds to just load the data in the application? Is there anyother way I can use to load the data? Right now I have just a test data later this data will be increased to 500+ recipes so that please suggest me according to that. Thankyou.
I am thinking to shift my database from firestore to mongoDB since I have no knowledge about it so I prefer to take help from the community.
as mentioned by Loc, fetching each recipe in its own query is probably the cause of the slow performance.
I'd get all the recipes by just fetching the entire collection once and then handle the data transfer from there on.
So something like this:
QuerySnapshot<Map<String, dynamic>> recipesSnapshot = firestore.collection('recipes').get();
for(QueryDocumentSnapshot doc in recipesSnapshot.docs){
// now do stuff with the data like recipes.add(Recipe.fromMap(doc.data! as Map);
}
This should reduce the runtime.
To answer your commented question you can do something like this:
for(QueryDocumentSnapshot doc in recipesSnapshot.docs){
recipes.add(Recipes(
recipeID: doc.id,
recipeName: doc.get('recipe_name'),
recipeDescription: doc.get('recipe_description'),
...
);
}
So just doc.get(FIREBASE_FIELD)
Alternatively you could use doc.data() as Map to get the whole doc as a Map and then access its content like any other map.
If you want to be fancy and have to load recipes in different parts of your app you could also add a function like this to your recipe class (I did not check if this works, but it should):
Recipe.fromQueryDocumentSnapshot(QueryDocumentSnapshot snap)
: recipeID = snap.id,
recipeName = snap.get('recipe_name'),
...
;
Then you could do it like this:
for(QueryDocumentSnapshot doc in recipesSnapshot.docs){
recipes.add(Recipe.fromQueryDocumentSnapshot(doc));
}

Results are different when application tested on a physical phone and on simulator

I am trying to solve an issue with my application. When I test it on a virtual device (iPhone), the query is working well and I am getting the document I am supposed to get. When I test the application on my physical phone, the application does not find any record.
I have checked the filters, they are the same. it is exactly the same code. I have never have this situation before. Please, do you have any suggestion?
Future myQuery ( time, energy, urgent, important ) async{
final uid = FirebaseAuth.instance.currentUser!.uid;
final path = 'Users/$uid/allTasks';
final currentQuery = FirebaseFirestore.instance.collection(path);
Query statusQuery = currentQuery.where('status', isEqualTo: 'Inbox');
// Query contextQuery = statusQuery.where('context', isEqualTo: );
Query timeQuery = statusQuery.where('time_Needed', isEqualTo: time);
Query energyQuery = timeQuery.where('energy_Needed', isEqualTo: energy);
Query urgentQuery = energyQuery.where('urgent', isEqualTo: urgent);
Query importantQuery = urgentQuery.where('important', isEqualTo: important);
final snapshot = await importantQuery.get();
final data = snapshot.docs;
if(data.isNotEmpty) {
return snapshot;
}
}
ElevatedButton(child:
const Text('FIND'),
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
EngageDisplayTasks(
time: timeSelectedPicker!, energy: energySelectedPicker!,
urgent: urgentWhere, important: importantWhere,
)));
}
),
#override
void initState() {
super.initState();
myQuery(time,energy,urgent,important).then((results) {
setState(() {
querySnapshot = results;
});
});
queryEngage(time,energy,urgent,important).then((results) {
setState(() {
querySnapshot = results;
});
});
}
Future queryEngage (time,energy,urgent,important) async {
await myQueryV2();
await myQueryV3 (statusQuery,time);
await myQueryV4 (timeQuery,energy);
await myQueryV5 (energyQuery,urgent);
await myQueryV6 (urgentQuery,important);
}
Future myQueryV2 ( ) async{
final uid = FirebaseAuth.instance.currentUser!.uid;
final path = 'Users/$uid/allTasks';
final currentQuery = FirebaseFirestore.instance.collection(path);
statusQuery = currentQuery.where('status', isEqualTo: 'Inbox');
return statusQuery;
}
Future myQueryV3 (statusQuery, time) async {
timeQuery = statusQuery.where('time_Needed', isEqualTo: time);
return timeQuery;
}
Future myQueryV4 (timeQuery, energy) async {
energyQuery = timeQuery.where('energy_Needed', isEqualTo: energy);
return energyQuery;
}
Future myQueryV5 (energyQuery, urgent) async {
urgentQuery = energyQuery.where('urgent', isEqualTo: urgent);
return urgentQuery;
}
Future myQueryV6 (urgentQuery, important) async {
importantQuery = urgentQuery.where('important', isEqualTo: important);
print ('urgent: $urgent');
print ('important: $important');
print ('time: $time');
print ('energy: $energy');
final snapshot = await importantQuery.get();
final data = snapshot.docs;
if(data.isNotEmpty) {
return snapshot;
}
}
You could write a single compound query like this. It is not necessary to get the results at each stage based on the code shown. You may need to create some composite indexes to improve optimization, but Firebase should notify you automatically if this is the case.
Future myQuery ( time, energy, urgent, important ) async{
final uid = FirebaseAuth.instance.currentUser!.uid;
final path = 'Users/$uid/allTasks';
final currentQuery = FirebaseFirestore.instance.collection(path);
try {
final snapshot = currentQuery
.where('status', isEqualTo: 'Inbox')
.where('time_Needed', isEqualTo: time)
.where('energy_Needed', isEqualTo: energy)
.where('urgent', isEqualTo: urgent)
.where('important', isEqualTo: important);
await snapshot.get().then((data) {
for (var doc in data.docs) {
print("${doc.id} => ${doc.data()}");
}
});
} catch (err) {
print(err);
}
}

FirebaseStorage - how to get all images in a folder

I'm trying to list all images in a created folder in FirebaseStorage.
Future getImages(String folderName) async {
final docRef = FirebaseStorage.instance.ref().child(folderName);
List imageRef = [];
docRef.listAll().then((result) async {
imageRef = result.items;
});
return imageRef;
}
FutureBuilder:
FutureBuilder(
future: getImages(images.first),
builder: (context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
List list = snapshot.data;
return Image.network(list.first);
} else {
return const Center(child: CircularProgressIndicator(),);
}
}),
I can not return anything from a then() function neither can I use its value outside its body!
I thought about returning a future object and then use it inside my FutureBuilder but again I need to return a widget and I can't do that inside a then() function
Try to use await in getImages to get the list result and return the items like this:
Future<List<Reference>> getImages(String folderName) async {
final docRef = FirebaseStorage.instance.ref().child(folderName);
final listResult = await docRef.listAll();
return Future.value(listResult.items);
}
But if you need the download url of the images, you have to add further code since the above will return a List of Reference, and the getDownloadURL method of Reference is also async. You could try this if you need a list of urls:
Future<List<String>> getImages(String folderName) async {
final docRef = FirebaseStorage.instance.ref().child(folderName);
final listResult = await docRef.listAll();
final urls = <String>[];
for (var item in listResult.items) {
urls.add(await item.getDownloadURL());
}
return Future.value(urls);
}

How to show displayName of contact as text?

I want to pick a random number from contact list and show it as Text. Below is what I came up with but when I insert showNext() somewhere on main.dart as text, I get Closure: () => Future from Function 'showNext': static.() instead of a number. How do I show a number?
Future<void> showNext() async {
var status = await Permission.contacts.status;
if (status.isGranted) {
var contacts = await ContactsService.getContacts;
var list = contacts;
list.shuffle();
randomNum= (list.first.phones?.first.value ?? '');
Text('$randomNum');
Future<Widget> showNext() async {
var status = await Permission.contacts.status;
if (status.isGranted) {
final Iterable<Contact> contacts = (await ContactsService.getContacts(withThumbnails: false));
var list = contacts.toList();
list=list.shuffle();
randomNum= (list.first.phones?.first.value ?? '');
return Text('$randomNum');
}
when you want use:
FutureBuilder<String>(
future: showNext(),
builder: (context, snapShot) {
if (!snapShot.hasData) {
return Container();
}
return snapShot.data;
},
)

flutter method checking if item is added to cart in firestore

I am having trouble with a method that is checking if the item is stored in the firestore database.
void add(BuildContext context, CartItem item) {
_items.add(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
_items.forEach((CartItem item) {
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
});
_instance = FirebaseFirestore.instance;
_instance!
.collection('cart')
.doc(authService.getCurrentUser()) //need to get logged in account's id
.update({
'cartProduct': FieldValue.arrayUnion([cartMap])
}).then((value) {
print(_items.length);
notifyListeners();
});}
The add Method adds the item to the firestore in a way like the example image.
However, after I delete the data using the remove method,
void remove(BuildContext context, CartItem item) {
_items.remove(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
// _items.forEach((CartItem item) {
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
// });
_instance = FirebaseFirestore.instance;
_instance!.collection('cart').doc(authService.getCurrentUser()).update({
'cartProduct': FieldValue.arrayRemove([cartMap]),
}).then((value) {
print(_items.length);
notifyListeners();
}); }
I check if the data is added to the cartProduct using isProductAddedToCart method and the result is still true. Also, when I print the _items.length, it doesn't decrease after I use the remove method.
bool isProductAddedToCart(Product? pro) {
return _items.length >= 0 ? _items.any(
(CartItem item) => item.product!.title == pro!.title) : false;
}
This is the code where I want to use the isProductAddedToCart method.
Consumer<CartService>(
builder: (context, cart, child) {
Widget renderedButton;
if (cart.isProductAddedToCart(widget.product) == false) {
renderedButton = DefaultButton(
text: "Participate",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.add(context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
} else {
renderedButton = DefaultButton(
text: "Delete",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.remove(
context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
}
return renderedButton;