How to fetch nested documents using streambuilder from Firestone in flutter? - firebase

My data is stored in nested form like
Collection->Document->Collection->Document->Collection->Document
I am fetching data using stream builder in flutter.
My aim is to create an instance of a class whose attributes are distributed in all the three layers of collection/documents.
After reading second layer, my function return the class object having partial values null, and shows the error on screen, but after some time it prints the values in the last layer.
I can not use the async/ await functionality here because of the stream builder.
I tried to make the nested function but no again.
I have tried sleep() function as well.
As you can below, After reading productVariant Snapshots, it skips the foreach loop and creates an instance of Order and return. However I'm also printing the values and they got print after the return command execute.
Code Snippet

Thanks for the answers, but I figured out the solution.
I used the nested FutureBuilders which returns promised widgets.
I modified my Order instance by updating variables with widgets.
Before
StreamBuilder -> Fetching Collections and Documents
After
StreamBuilder -> FutureBuilder to Fetch Collection/Document ->FutureBuilder - >To fetch inner Collection/Document

Related

Is there a way to retrieve realtime firebase map as a linkedhashmap or at least maintain the order it is saved in

I have a map of string boolean pairs saved on firebase realtime database and was wondering if there is a way to retrieve it in kotlin as a linkedhashmap such that the original order remains in place.
I have tried typecasting to a linkedhashmap and got an error that hashmap cannot be typecasted to linked hashmap, I then tried calling the linkedhashmap constructor method with the parameter being the data from the database as a hashmap but that does not maintain the order
Properties in JSON are by definition not in any specific order.
While you can retrieve data from Firebase in a specific order, by calling one of its orderBy... operations, that order will be lost when you call .value in the DataSnapshot as DataSnapshot.value returns a Map, which is unordered again.
If you want to retrieve the nodes in a specific order:
Call orderBy... to get the nodes in a specific order.
Loop over the children of the snapshot you get back to process them in order, and only call value on each specific child node.

How to create one stream listening to multiple Firestore documents created from list of documents references in Flutter

Im trying to create one stream, that is using multiple documents references that are stored and fetched from Firebase Firestore.
Lets say I have two collection named users and documents. When user is created he gets document with his id in users collection with field named documentsHasAccessTo that is list of references to documents inside documents collection. It is important, that these documents can be located in different sub collections inside documents collection so I dont want to query whole documents and filter it, in order to save Firestore transfer and make it faster I already know paths to documents stored in documentsHasAccessTo field.
So for example, I can have user with data inside users/<user uid> document with documentsHasAccessTo field that stores 3 different document references.
I would like to achieve something like this (untested):
final userId = 'blablakfn1n21n4109';
final usersDocumentRef = FirebaseFirestore.instance.doc('users/$userId');
usersDocumentRef.snapshots().listen((snapshot) {
final references = snapshot.data()['documentsHasAccessTo'] as List<DocumentReference>;
final documentsStream = // create single query stream using all references from list
});
Keep in mind, that it would also be great, if this stream would update query if documentsHasAccessTo changes like in the example above, hence I used snapshots() on usersDocumentReferences rather than single get() fetch.
The more I think about this Im starting to believe this is simple impossible or theres a more simple and clean solution. Im open to anything.
You could use rxdart's switchMap and MergeStream:
usersDocumentRef.snapshots().switchMap((snapshot) {
final references = snapshot.data()['documentsHasAccessTo'] as List<DocumentReference>;
return MergeStream(references.map(ref) => /* do something that creates a stream */));
});

How to get a specific Firestore document of a certain collection with a ListView.builder

I have a collection in my firestore database named as 'testCrud', where I have carModel, and carColor.
I am trying to get carModel value in my dashboard page.
I am using QuerySnapshot cars;
Rest of the code is in picture, I don't know if data[] is deprecated?
[1]: https://i.stack.imgur.com/m2abq.png
data is no longer a property, it's a method.
So, try:
cars.docs[i].data()['carModel']
Getting a snapshots' data via the data getter is now done via the data() method.
https://firebase.flutter.dev/docs/migration

Can we trigger firebase cloud functions when we create a collection (not "document")?

I am trying to achieve a scenario where firebase triggers only once when a collection is created and not every time that a document is added to the collection. Let's say I want it to trigger only for the first document added to the collection and not for every other document added to the same collection. How can that be done? Please help !!!
There is no such trigger for Cloud Functions. Your trigger path must specify exactly one document, or use wildcards to specify a path that could possibly match many documents.
If you want to know what a collection contains its first document, you will have to either:
Maintain a count of documents in that collection (perhaps in yet another document in another collection), and trigger of the change of that value when it goes from 0 to 1.
Query all of the documents in the collection where a document was just created in order to figure out if it was the first one.
Both of these requires a fair amount of extra code - very much not trivial to implement correctly for arbitrary collections. They could also run into problems under heavy load. If these options won't work for you, I suggest figuring out another way to get you function to trigger at the right time.
While It's not possible to do directly. You can check if collection contains any elements, and if it does it means that it exists.
const result =await firestore.collection("collection").limit(1).get()
if(result.size){
// Collection exists
}

How do I stop Firebase from creating an additional nested object or how can I access the newly generated string?

Problem: Whenever I add an order to the orders array, an additional nested array element(-KOPWA...) gets added. I wouldn't mind except, I don't know how to access that nested string to access it's child nodes.
Example of database node for users below:
firebase.database().ref('users/'+userIdState+'/orders/'+<<unique numbervariable>>).push({
"order":{"test":"product","quantity":2}
});
I'm using the above code to push new json objects with a unique number to the firebase array. Still the nested array with the weird strings gets generated.
Can anyone help me understand how to either: create my own nested array with my own unique string or how to access the nested string that gets generated from firebase so I can access it's children nodes.
Multiple instances of nest arrays will be generated by users.
Any help is much appreciated.
Thanks,
Moe
You're experiencing this behaviour because Firebase's push is not the same as an array push. I recommend reading this article to understand how it works.
As for a solution, you can simply change push to set in your code. This will create the structure you were (presumably) expecting, that is
1:
order:
...
This is however potentially unsafe, if you allow concurrent writes (i. e. if the "unique number" in your example is not always unique).
Afaik Firebase recommends using push to safely create collections/"arrays". You can retrieve the generated key by calling the key property on the reference returned by push. Like this:
var ref = firebase.database().ref('users/'+userIdState+'/orders/'+<<unique numbervariable>>).push({
"order":{"test":"product","quantity":2}
});
var generatedKey = ref.key; // the value you're looking for
If you decide to use it, you can probably just drop the order number you have right now and just use the generated one.

Resources