How to properly get data from Firebase Firestore in Flutter? - firebase

I have a Firebase Firestore database as you can see in the picture. I'd like to get every document from the questions collection with their fields.
I found the following solution on the internet:
//in this list we store the data
List adatok = [];
Future<void> getData(){
databaseReference.getDocuments().then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
);
}
);
}
My problem is that when I call this function (in an onPresed() function of a button), for the first time of pressing the adatok list is empty. But when I press the button for the second time, it contains every data which I wanted to acquire.
Did I do something wrong? Is there another way to get the data?
The layout of the database

Use the code below:
List adatok = [];
Future<void> getData() async{
QuerySnapshot snapshot = await databaseReference.getDocuments();
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
}
By this way, The program waits until it gets all the documents.
and then adds it to your snapshots.
Also you have to change your onPressed() function to async/await like the following:
onPressed:() async{
await getData();
/...
}
So the program waits until getData() finishes.

Related

Flutter-Firestore: - Code to retrieve data from firestore then save/use it

I am very new to Dart, and coding in general. I have produced this code after watching tutorials on YouTube. For the most part, I have been able to troubleshoot most of my problems on my own, here I feel I need some help. I wanted to extract all the fields from a document and use it. I have tried a few codes but there is no proper solution anywhere online.
Here is the code I used to retrieve it:-
documentID = '9zjwixClgwR1Act1OlPK'
firebaseGetData(documentID){
firebaseFirestore.collection('course').doc(documentID).get().then((value) {
print(value.data());
});
}
Here is my database file structure:-
I want to store all the fields in variables and use them. please help me with the correct code, please.
There are two ways to retrieve data stored in Cloud Firestore. Either of these methods can be used with documents, collections of documents, or the results of queries:
Call a method to get the data
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
getDoc(docRef)
.then((doc) => {
console.log(doc.data(),doc.id)
})
Set a listener to receive data-change events.
To get real-time data when you set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
onSnapshot(docRef,(doc) => {
console.log(doc.data(),doc.id)
})
For more information, kindly check link1 & link2
Firstly you need to create firestore instance. Your function must be async and return a Future value. Also, you can check this document.
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<Map<String, dynamic>> firebaseGetData({required String documentID}) async {
DocumentSnapshot ds =
await _firestore.collection("course").doc(documentID).get();
Map<String, dynamic> data = ds.data() as Map<String, dynamic>;
print(data["videoDescription"] as String); // check if it null or not
return data;
}
// creating a instance variable
final CollectionReference firestoreInstance =
FirebaseFirestore.instance.collection('course');
void _loadUserData() async {
await firestoreInstance.doc(documentID).get().then((event) {
// you can access the values by
print(event['isDOne']);
print(event['lastViewedOn']);
print(event['lectureNo']);
print(event['videoDescription']);
print(event['videoUrl']);
});
}
call the _loadUserData() function whenever you need to fetch the data.

Rebuild widgets when a subcollection recieves data in another widget

I have 6 widgets that all share the same data with only one receiving the data from the stream
AllClasses() //displays all of classes and is the start of getting the data from the stream
ClassList(data) //displays nothing but builds the list view and holds the index of what class is to be displayed in classtile widget
ClassTile(data) //presents the data from the index of the data passed in from ClassList
ClassPage(data) //when a classtile is clicked this screen is presented
HomeworksList(data) //goes to this widget when the homeworks button is clicked shows all the homeworks that are available for the specific class clicked on
HomeworkTile(data) // shows the tile for each homework
As you can see I get the data once then pass it down the widget tree multiple times. What has become an issue is that when I am showing the homework list which is 5 widgets down the widget tree from where the data is coming from I have the option to add another homework to the homework list. technically adding it to the firestore database.
The problem is that when I add a Homework it does not refresh the data or rebuild any widgets until I go all the way back to the "AllClasses()" widget.
so to reiterate, I have a widget that shows all of the homeworks and in this widget you are able to add a homework and when you do it updates the subcollection, but does not rebuild the widget that shows all of the homeworks until I go back a couple widgets from where the data is first grabbed
the database schema is set up like this:
Classes {
subcollections:
Homework {
...
}
fields:
}
perhaps its the way I have my database and instead I should have a Homeworks collection that is outside of everything. or maybe its because I am using a generator future to produce the same thing as a stream by using a never ending while loop. either way I don't understand streams enough to understand what to do next, I have been working on this since 8am today and I have tried just about everything in my power. I may just use Homeworks as a seperate collection instead of a subcollection the problem with this is knowing which class I am in when I click on homework.
Stream<List<ClassData>> get fetchClassdata async* {
QuerySnapshot snapshot = await classesCollection.getDocuments();
// while (true) {
List<ClassData> _classList = List<ClassData>();
await Future.forEach(snapshot.documents, (element) async {
QuerySnapshot pre = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Pre")
.getDocuments();
QuerySnapshot homeworksSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Homework")
.getDocuments();
QuerySnapshot notesSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Notes")
.getDocuments();
QuerySnapshot testsSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Tests")
.getDocuments();
List<Preq> _preList = List<Preq>();
List<Homework> _homeworkList = List<Homework>();
List<Note> _notesList = List<Note>();
List<Test> _testsList = List<Test>();
pre.documents.forEach((preClass) {
Preq preqData = Preq.fromMap(preClass.data);
if (preClass.data != null) {
_preList.add(preqData);
}
});
homeworksSnapshot.documents.forEach((hwork) {
Homework homeworkdata = Homework.fromMap(hwork.data);
_homeworkList.add(homeworkdata);
});
ClassData data = ClassData.fromMap(
element.data, element.documentID, _preList, _homeworkList);
if (data != null) {
_classList.add(data);
}
});
yield _classList;
// }
}
}

async operation within an async function

For an instance, let's suppose I am calling a function in initState which gets some documents from the Firebase collection. I am iterating on those documents using async forEach and need to perform an await operation to get some data from another collection from firebase and saving them in a list then returning after the forEach is finished. But the returned list is empty as the second await function completes after return statement. How do I handle this? I have a hard time understanding Asynchronous programming so please a detailed explanation will be highly appreciated.
The code here is just an example code showing an actual scenario.
Future getList() async {
//These are just example refs and in the actual refs it does print actual values
var collectionOneRef = Firestore.instance.collection('Collection1');
var collectionTwoRef = Firestore.instance.collection('Collection2');
List<Map<String, dynamic>> properties = [];
QuerySnapshot querySnapshot = await collectionOneRef
.getDocuments()
.then((query) {
query.documents.forEach((colOneDoc) async {
var colOneID = colOneDoc.documentID;
await collectionTwoRef.document(colOneID).get().then((colTwoDoc) {
Map<String, dynamic> someMap = {
"field1": colTwoDoc['field1'],
"field2": colTwoDoc['field2']
};
properties.add(someMap);
properties.sort((p1, p2) {
//sorting based on two properties
var r = p1["field1"].compareTo(p2["field1"]);
if (r != 0) return r;
return p1["field2"].compareTo(p2["field2"]);
});
print(properties); //this prints actual data in it
));
});
});
});
print(properties); //This prints a blank list as [] and obviously returns blank list
return properties;
}
And now when I call this function in an initState of a stateful Widget and display it somewhere, it display a blank list. BUT, after I "Hot Reload", then it displays. I want to get the data and display it without hot reloading it. Thanks in advance
Sounds like you need to await the whole function itself in the block of code where you are calling getList().
you are async'ing and awaiting inside the function, and that looks fine which is why you are getting results when hot reloading. But it might be the case that you're not actually awaiting the entire function itself in the code that is calling this. Please Check.

Issue adding element to list

I'm a total newbie to Flutter and I'm trying to add some data from Cloud Firestore to a list in Flutter, but having issues. I try to add the element, but after executing, the element isn't there. It's not throwing an exception or anything either. Maybe someone else has some advice for me!
I have tried changing the type of list (capture the doc from Cloud Firestore instead of data within the doc, same issue), I have also debugPrinted the data I am trying to store to make sure it exists, it does. I have done basic troubleshooting like running flutter clean as well. I am on the latest version of Flutter.
Firestore db = firestore();
List<String> getString() {
var dataList = new List<String>();
db.collection('Users').get().then((querySnapshot) {
querySnapshot.forEach((doc) {
dataList.add(doc.get('First name'));
});
});
debugPrint(dataList.first);
return dataList;
The list is empty, though it should contain the "First name" field on this Cloud Firestore doc. Again, verified the data does exist and prints when calling debugPrint.
The db.collection('Users').get() is a async function, so debugPrint(dataList.first); executes before of the end of your firestores get, because that your array returns empty.
If you try it:
db.collection('Users').get().then((querySnapshot) {
querySnapshot.forEach((doc) {
dataList.add(doc.get('First name'));
});
debugPrint(dataList.first);
});
You will see your data.
You can use await to wait the call finishes, so you must return a Future and use async key word on function declaration. This is a conceipt that you must know of flutter async functions (Async Flutter). So, the code below can solve your problem.
Firestore db = firestore();
Future <List<String>> getString() async {
var dataList = new List<String>();
var result = await db.collection('Users').get();
result.forEach((doc) {
dataList.add(doc.get('First name'));
});
debugPrint(dataList.first);
return dataList;
}

Firebase Realtime Database Query All Items in Flutter

I'm trying to get all the stored items inside the firebase realtime database and i'm not able to get them. Here the function that i'm using. I want to get all the keys stored inside the bdd(attached a screenshot of the bdd). The size of the returned items is 0 always.
Future<int> getEntriesNumber() async {
final response = FirebaseDatabase.instance
.reference();
var entries = [];
response.onValue.forEach((v) => entries.add(v));
print("getEntries $entries");
return entries.length;
}
Bdd Data
Thank you!
Solved with this:
DataSnapshot response = await FirebaseDatabase.instance
.reference().once();
print(response.value.toString());
You can solve with something like this:
final databaseReference = FirebaseDatabase.instance.reference().child('//hereTheCollectionName');
databaseReference.once().then((DataSnapshot snapshot) {
//snapshot.value will contain each register in your database.
});
You should use async/await to wait for all registers.

Resources