Firestore fetch never executes in Flutter Code - firebase

I have an int named "length" in my code and I am trying to change it's value from a field in my Cloud Firestore:
int length;
_handlePressed(context) {
DocumentReference postReference = Firestore.instance.collection(ISBN).document(post);
postReference.get().then((datasnapshot){
if(datasnapshot.exists) {
length = datasnapshot.data["length"];
print(length.toString());
}
});
}
The field "length" is stored as a Number Type in my Firestore.
The problem is that the print operation does not execute and printing length elsewhere shows null in the console. What am i missing?

First, make sure that _handlePressed is really called then update the state with setState when using a StatefulWidget:
int length;
_handlePressed(context) {
DocumentReference postReference = Firestore.instance.collection(ISBN).document(post);
postReference.get().then((datasnapshot){
if(datasnapshot.exists) {
setState(()
length = datasnapshot.data["length"];
);
print(length.toString());
} }); }

Related

Arrays updates not seen in snapshot listener Firestore

Let's say I have a simple document which looks like this :
I am attaching a snapshotListener to this collection.
the code is in dart but it's equivalent logic to any langage i have tried :
streamSubscription = query.snapshots().listen((event) {
print("Listening event : " + event.docs.toString());
for (DocumentChange documentChange in event.docChanges) {
switch (documentChange.type) {
case DocumentChangeType.added:
addDoc(documentChange.doc);
break;
case DocumentChangeType.modified:
updateDoc(documentChange.doc);
break;
case DocumentChangeType.removed:
removeDoc(documentChange.doc);
break;
}
}
});
And the updateDoc() method is :
void updateDoc(DocumentSnapshot documentSnapshot) {
Map<String, dynamic> data = documentSnapshot.data() as Map<String, dynamic>;
TestObject test = TestObject.fromJson(data);
print(test);
}
Now if i change the name in the console, the name value is changed and we can see it in the print(test).
However, if i remove the entry secondtestvalue from the array, the updateDoc is triggered but the print(test) still displays the value... Which means my array is not updated.
Is this a bug or i am missing something ?

A function prints the value but It's not printed on another function when returned

I'm trying to get the near by location using firebase query and it goes well. This the function that gets the nearby location.
Future<List<DocumentSnapshot>> nearbyLocations() async {
CollectionReference collectionRefer =
FirebaseFirestore.instance.collection('locations');
double radius = 10;
String field = 'position';
List<DocumentSnapshot> docList;
GeoFirePoint center = await getCurrentLocation();
// print(center);
Stream<List<DocumentSnapshot>> stream = geo
.collection(collectionRef: collectionRefer)
.within(center: center, radius: radius, field: field, strictMode: true);
stream.listen((List<DocumentSnapshot> documentList) {
if (documentList.length > 0) {
print(documentList[0].data());
docList = documentList;
} else {
return {};
}
});
}
I know that the query will return only one data. So, I printed on the first value in the above function.
The problem arises when the documentList is returned.
loadData() async {
documentList =
await GeoLocator().nearbyLocations();
}
When I call this above function, It prints null. But When I tried to print in the nearbyLocations() It print the data. But not when I Call loadData(). I'm going to use this returned data in listview.
You are mixing await, streams and then. This is probably too much to keep in mind at the same time.
Focus on one method at first. I suggest async/await since that is the easiest.
Your nearbyLocations method does not return anything. You did not define a type and it does not have a return statement either. Yet, you seem to expect it to return a Future<> with a specified type.
Make sure you crank up your warnings and use the pedantic package to have your analyzer notify you when you forget those things.
When you actually declare your method fully, your warnings should show you that you have no return in your method.
I don't have a compiler here or packages to include, but this seems to be what you really want:
Future<List<DocumentSnapshot>> nearbyLocations() async {
final collectionRefer = FirebaseFirestore.instance.collection('locations');
final radius = 10.0;
final field = 'position';
final center = await getCurrentLocation();
final stream = geo
.collection(collectionRef: collectionRefer)
.within(center: center, radius: radius, field: field, strictMode: true);
return stream.first;
}

Firestore Flutter How to get a list all the documents and its data inside a collection?

I have been working to get a list of all the documents inside a firestore collection. I want to display all details of all documents inside a collection.
My document tree is ask follows-
'groups' COLLECTION----->Documents w 'groupID' as reference------>'tasks' COLLECTION------>Documents w 'taskId' as reference.
Now I want to get all documents and its details inside 'tasks' collection for a particular groupID.
Future<MyTask> getCurrentTask(String groupId) async {
MyTask retVal = MyTask();
try {
DocumentSnapshot _docSnapshot =
await _firestore.collection("groups").document(groupId).collection("tasks").get();
retVal.taskId = taskId;
retVal.taskName = _docSnapshot.data['taskName'];
retVal.dueTime = _docSnapshot.data['dueTime'];
retVal.member =_docSnapshot.data['member'];
retVal.completed = _docSnapshot.data['completed'];
} catch (e) {
print(e);
}
return retVal;
}
I tried this but it doesnt work as "The method 'get' isn't defined for the type 'CollectionReference'."
How to get around this please?
Simply do like this:
Firestore.instance.collection("groups").document(groupID).collection("task").snapshots().listen((event) {
retVal = event.documents.map((e) => MyTask.fromJson(e.data)).toList();
});
I assume your MyTask model already have fromJson method so do it like that. And change your retVal to List: List<MyTask> retVal = [];. It will get all of your document and also listen whether there's change's on the collection.

How do you get a a collection of documents from firestore and turn it into a list in flutter?

I have been trying to figure out how to query Firestore and save the output to a list so that I can use it in another part of the app.
I have tried to save it into a list but I get "Unhandled Exception: type 'double' is not a subtype of type 'List dynamic'".
I then tried to save it as a List but then I get "Unhandled Exception: type 'double' is not a subtype of type 'List double'
I also tried to output it as a map but I think I'm missing something there because it won't compile.
Here is the function:
setMainDebt()async{
final uid = await Provider.of(context).auth.getCurrnetUid();
final fireStoreData = await db.collection('userDebts').document(uid).collection('debts').orderBy('balance').getDocuments();
for(var theData in fireStoreData.documents){
final List<double> value = theData.data['balance'];
print(value);
}
}
I think you are trying to assign a double value directly to a List. you should add them instead.
List<double> list=[];
final fireStoreData = await db.collection('userDebts').document(uid).collection('debts').orderBy('balance')
fireStoreData.getDocuments().then((val)=>{ val.documents.forEach((doc)=>{ list.add(doc.data['balance']) }) });
It seems like when you call theData.data['balance'] (which can be a DocumentReference not var), you get a list of double values, not a double value. Check your database. You must be storing it as a list. To overcome that, edit your code like this.
for(var theData in fireStoreData.documents){
for (List l in theData.data['balance']){
final List<double> value = l;
print(value);
}
}
You can make a List<double> and then add data in it and then use it where you want.
You are currently getting error because you can't assign a double type value in aListtype
Try:
Future<List<double>>setMainDebt()async{
List<double> list=[]; // make an empty list
final uid = await Provider.of(context).auth.getCurrnetUid();
final fireStoreData = await db.collection('userDebts').document(uid).collection('debts').orderBy('balance').getDocuments();
for(var theData in fireStoreData.documents){
list.add(theData.data['balance'] as double); // typecast data as double and add it in list
print(value);
}
return list; // return list
}

Flutter Only create item which documentID matches String in array in Firestore

I'm still new to Flutter and Firestore, and have a problem where I basically want to only populate a list with items in the collection "brites" if (and only if) the documentID also appear as a String in an array in another Firestore collection called "users" > "bookmarks" > array (containing Strings with documentID:s).
I have a hard time knowing where to start, I believe mainly due to my currently vague understanding of Firestore and asynchronous streams and queries. Maybe where() or map() is the solution, but what that is concrete is over my head currently.
List<Widget> populateBriteList(AsyncSnapshot snapshot, int x, bool isBookmarksSection) {
List<Widget> list = new List<Widget>();
BriteShowItem _briteContent(j) {
return BriteShowItem(
briteID: snapshot.data.documents[j].documentID,
imagePath: snapshot.data.documents[j]["imagePath"],
title: snapshot.data.documents[j]["title"],
author: snapshot.data.documents[j]["author"],
published: snapshot.data.documents[j]["published"],
duration: snapshot.data.documents[j]["duration"],
isBookmarked: snapshot.data.documents[j]["isBookmarked"],
);
}
if (isBookmarksSection) {
for (int i=0; i<x; i++) {
//Here only list.add briteContent(i) if the "documentID" in passed in
//Snapshot ("brites" collection)
//is equal to a string in "bookmarks" array in "users" collection
list.add(
_briteContent(i)
);
}
} else {
for (int i=0; i<x; i++) {
list.add(
_briteContent(i)
);
}
}
return list;
}
So one thing is that when you are actually building the widgets that depend on some data in firestore, you ultimately already need to have that data. That doesn't mean you can't return a temporary value while you are waiting for a Future to resolve. But, in this case, it looks like you are calling this method once you already have the data. So maybe just pass the array of bookmarks in, also (that said, a method like this with a bunch of arguments is a good indicator that things are getting out of hand and some more structural changes are needed - for example, by splitting up the method depending on the conditions and calling different methods as needed):
List<Widget> populateBriteList(AsyncSnapshot snapshot, int x, bool isBookmarksSection, AsyncSnapshot bookmarkSnapshot) {
...
if (isBookmarksSection) {
for (int i=0; i<x; i++) {
if(bookmarkSnapshot.documents.where((document) => condition(document.data)).length > 0){
list.add(
_briteContent(i)
);
}
}
In this case, 'where(someTest)' is called on an iterable list, (documents), each element is passed into the someTest method, and if the result is true, that element is passed into the list. So if the list is greater than 0, at least one element satisfied that condition.

Resources