Access n-th document in Firestore with Flutter - firebase

I first want to determine the length of my collection (i.e. how many documents are in my collection?) and then randomly grab one of the documents and display certain fields in it.
In my Scaffold I have the following StreamBuilder so far:
StreamBuilder(
stream: _wordsFoods.snapshots(),
builder: (context, snapshot){
return _buildList(context, snapshot.data.documents);
}
)
_buildList returns the length of the collection "words":
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return Center(child: Text(snapshot.length.toString()));
}
But how do I now say that I want the (e.g.) second document in my collection? How do I connect it with a query, so I can say I want a certain field within the second document of my collection?

There is no built-in count operation in Cloud Firestore. To determine the number of documents, you either have to retrieve all of them, or keep a separate counter. Since retrieving all documents to determine a number is highly wasteful of bandwidth, most developers go for the second option where they implement a counter field in a separate document in their database, and then update that on every add/delete operation.
There also is no operation to get a document at a certain offset in the client-side SDKs for Firestore. And while the server-side Admin SDKs do offer an offset() method, this one under the hood actually reads all documents that you're telling it to skip. So while it saves on bandwidth for those document, they are still read and charged to your quota.
To efficiently retrieve a random document from Firestore, have a look at Dan's answer here: Firestore: How to get random documents in a collection

Related

How does Firestore document snapshot work?

when a new document is added, snapshot fetches all the documents including the new ones or only the newly added ones ? If it fetches all the documents every time then it will add to the billing cost. How to get around this problem ?
StreamBuilder(
stream:Firestore.instance
.collection('chat')
.orderBy('timeStamp', descending: true).snapshots(),
builder: (context, streamSnapshot) {}
);
While your snapshots() listener stays active, the server actively monitors for changes that are relevant to your listener. When there are such changes it only sends you new documents, or documents that were changed, to your client. The client then merges those updates with its local data, and presents you with a new complete QuerySnapshot.
According to the official doc : Here
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.
Set a listener to receive data-change events.
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.
You can get an array of the document snapshots by using the docs property of a QuerySnapshot. After that you'll have to loop through getting the data of the doc snapshots looking for your doc.
OR if you don't actually need the full QuerySnapshot, you can apply the filter using the where function before calling get on the query object
These are the most efficient way to get documents.

How to fetch only documentIDs [Firebase-Flutter]

In my firebase's database I have Users and every user has multiple stores that he ordered from and every store has multiple orders.
To fetch all the orders for specific store I write the following query and it works fine.
QuerySnapshot result = await Firestore.instance
.collection('users')
.document(userID)
.collection('Stores').
document(storeID).getDocuments();
However, I do not need that. I just need the stores that the user ordered from. In other words, I need list of storeIDs for specific user.
Here is my code but it doesn't work.
QuerySnapshot result = await Firestore.instance
.collection('users')
.document(userID)
.collection('Stores').getDocuments();
I just want the IDs
It's not possible with web and mobile clients to get only the IDs without the entire set of documents and their data. If you want a list of all IDs for all documents in a collection or subcolleciton, you're going to have to query that collection as you currently show in the second example. You can easily extract the IDs from the returned documents in the QuerySnapshot. But you are still paying the cost of a document read for each document in the collection, and waiting for all of their contents to transfer.
If you want, you can create your own backend endpoint API to use a server SDK to query for only the IDs, and return only the IDs, but you are still paying a document read for document.

How to sort firebase documents by the size of a list in Flutter?

Could someone explain to me how I can order documents on Firebase by the size of a list?
I have this 'rec' list on several items, but I can only sort it as:
body: FutureBuilder<QuerySnapshot>(
future: Firestore.instance
.collection("products")
.document(snapshot.documentID)
.collection("items")
.orderBy("rec")
.getDocuments(),
https://i.stack.imgur.com/3yV9D.png
You need to add a recSize key to your documents and a firebase function that recalculates the size of your list every time the list changes. Then order using recSize.
Firestore does not provide us with metadata, hence in order to get the size of a document stored in a collection you can proceed with one of the following:
As Henok pointed out, use a field to store the current size of the document and use it to sort your data on the back-end side.
Download your unsorted documents and sort them on the client according to their size.
Please check out this similar thread which you may found useful in both cases.

Is there a way to sort a collection when creating random documents inside a collection?

Is there a way to use orderBy( ) when creating random documents inside a collection such that the newly created one will always come after the previous one.
In my case the collection is called ‘Chats’ and documents are created at random and I loop through them to reveal messages. I want an order where newly created documents will always come after the previous ones. how do I achieve this?
firestore
.collection(InterviewsInformation)
.document(InterviewID)
.collection('Chat')
.add({
'MessageSender': MessageSender,
'MessageText': messageText,
});
I also tried sorting the collection by using a timestamp
firestore
.collection(InterviewsInformation)
.document(InterviewID)
.collection('Chat')
.add({
'MessageSender': employer['EmployerName'],
'MessageText': messageText,
'CreatedAt': FieldValue.serverTimestamp()
});
firestore
.collection(InterviewsInformation)
.document(InterviewID)
.collection('Chat').orderBy("CreatedAt", descending: true) ;
still doesn't work messages appear at random, can someone help?
Turns out that documents wont be created by random in the cloud firestore but your query in the stream builder can help show them in a sorted order
stream: firestore
.collection(InterviewsInformation)
.document(InterviewID)
.collection('Chat').orderBy('CreatedAt')
.snapshots(),

How to read a firestore value in a map?

I'm trying to read the value for exp_date in my flutter app as seen in this picture:
The field/value pair is in a map called Card which is in a sub collection called sources . I can read the value by putting in the DocId for the sources collection(the other docId is the firebase user uid) with the following:
StreamBuilder(stream: Firestore.instance.collection('stripe_customers').document(userId).collection('sources').document('qRvDob75kTzhT3').snapshots(),builder: (context,snapshot){
if(!snapshot.hasData){
return new Text("Loading");
}
var userDocument = snapshot.data;
return new Text(userDocument["card"]['exp_year'].toString());
},),
But obviously this isn't very practical. How do I access the Card map value without knowing the document id?
There are two ways to get the contents of a document:
Know its entire, unique path.
Make query against a known collection to get matching documents.
If you don't know the id required by #1, you will have to try #2. But since you don't seem to have have a way to filter the documents in that collection, you will have to fetch ALL of the documents. This is probably not what you want to do for scalability purposes.
Give some consideration about how you want to find the data in Firestore before you write the documents.

Resources