How firestore count read on flutter - firebase

I have several question about how does firebase count read in my flutter app,
i have an app which use multiple firestore snapshot as stream like this:
_firestore
.collection(salesOrderPath)
.where("unit", isEqualTo: 1)
.snapshots()
_firestore
.collection(salesOrderPath)
.where("status", isEqualTo: 2)
.snapshots()
This two stream contain some same document, does that same document counted twice or once?
2.If i have multiple where filter on my firestore snapshot like this:
_firestore
.collection(salesOrderPath)
.where("unit", isEqualTo: 1)//10 Document
.where("status", isEqualTo: 2)//4 Document
.orderBy('creationDate',descending: true)
.snapshots()
Would i be charged by 10 read or just 4?
Maybe not related, but i saw something called Network egress as limit in the firebase pricing, what is this network egress meaning actually is it for storage or for firestore?
How long does cache from firestore in our app last before we need to reread it again from firestore?
I am new at this and dont quite understand a lot of thing, thankyou so much for answering

I think you should definitely watch video on Firebase Guide regarding pricing (actually I suggest to watch all of them).
I don't think you will find better description of pricing.
I guess question#1 is 2 reads as there are 2 queries. Question#2 anwser is 4 reads. Question#3 - if you watch the video you will know that this is rather negligible cost.
Now point 4#. Unfortunately I don't know, but I found something that might be interesting for you here.

Firestore bills you for your result set. So if your whole query returns 10 documents from a million documents. You only get billed for those 10 documents.
Network Egress is:
Network traffic that begins inside of a network and
proceeds through its routers to a destination somewhere outside of the
network
So if you ask for one document, you get billed for that 1 read plus the 'work done' for firestore to get that document for you.
The cache does not have an explicit expiry date. It will expire if it needs to make more space for new data or there was a deletion server-side and your cache now needs to resync. The size of the cache is 40MB.
Like others have mentioned I highly recommend their series on youtube

Related

how can I get the length from this query snapshot on firestore firebase?

I am getting videos from firebase firestore by using this query:
FirebaseFirestore.instance.collection('videos').where('uid',isEqualTo: widget.uid).get();
I am getting the videos of particular user id but how can I get the length of videos that how many videos has been posted/stored by this particular current user 'uid'. I want to know the numbers of videos that user holds. So basically I need this to hide the container where I display videos, if there is no video by this user id.
If I correctly understand your question, you should use the size property, as follows for example.
FirebaseFirestore.instance
.collection('videos')
.where('uid',isEqualTo: widget.uid)
.get()
.then((QuerySnapshot querySnapshot) {
Print(querySnapshot.size);
});
HOWEVER, you should note that this implies that you read all the documents corresponding to the query each time you want to get the number of videos and, therefore, it has a cost. If your collection is and stays small, using the size method can be a good approach.
But if the collection is going to contain a lot of docs and you often need to get the number of docs, better use another approach, like maintaining one or more counters. See these answers for examples: 1, 2 and 3.

Am I using Firestore Indexes correctly?

I've been recently making use of Flutter and Firebase to build some Networking Apps similar to the likes of LinkedIn. One of the App's features is its ability to match your profile with other users registered in the database based on factors such as location and the type of work you do. To do that I've been using Firestore snapshots with some conditions applied. Two of these conditions ask Firebase to sort the users by 'Last Active' and to only read documents of users that have signed in within the past month. In order to declutter the results and decrease the number of documents reads that are requested at a time. This is one example of a firebase snapshot I'm using:
Firestore.instance
.collection('usersIsb')
.where('Set', isEqualTo: true)
.where('Account Type', isEqualTo: _tempType)
.where('Services List', arrayContainsAny: _tempServices)
.where('Location', isEqualTo: widget.userData.location)
.where('Last Active', isGreaterThanOrEqualTo: widget.dateLimit)
.orderBy('Last Active', descending: true)
.limit(10)
.snapshots()
Naturally, because of the complexity of the request, Firebase asks me to create an Index for it, I've done that, and everything seems to be working correctly without any noticeable slowdowns or issues. However, I have a couple of questions that I'd like answered:
Are these indexes real-time? As in updated every time a new user document is created?
How many Indexes can I have in one Firestore database? The indexing process sounds intensive so I'm assuming there are drawbacks.
Is this how it's supposed to be done in the first place? It feels like I'm doing something wrong...
Extra: These are the Indexes I currently have enabled in my Firestore database.
This is my first post on the platform so feel free to ask for more information if needed, any advice on how to achieve the objective more efficiently is also appreciated.
Are these indexes real-time? As in updated every time a new user document is created?
Yes
How many Indexes can I have in one Firestore database?
The documentation on index limits says:
Maximum number of composite indexes for a database: 200
Maximum number of single-field index exemptions for a database: 200
You should read through the entire documentation there to understand all the limits.
Is this how it's supposed to be done in the first place?
That's a matter of opinion. You can do whatever you want within the documented limits. If your indexes and queries work for your use cases, then that's fine.

Firebase query charges additional reads?

How does firebase query works?
for example, if i write this query,
var collectionReference = FirebaseFirestore.instance
.collection('collection')
.where(cond)
.where(cond2)
.where(cond3);
So is this gonna return only the documents which fit the conditions?
AND I AM GOING TO GET CHARGED ONLY FOR THOSE DOCUMENT READS?
from docs TL:DR
Charges for reads have some nuances that you should keep in mind. The following sections explain these nuances in detail.
Listening to query results
Cloud Firestore allows you to listen to the results of a query and get realtime updates when the query results change.
When you listen to the results of a query, you are charged for a read each time a document in the result set is added or updated. You are also charged for a read when a document is removed from the result set because the document has changed. (In contrast, when a document is deleted, you are not charged for a read.)
Also, if the listener is disconnected for more than 30 minutes (for example, if the user goes offline), you will be charged for reads as if you had issued a brand-new query.
Managing large result sets
Cloud Firestore has several features to help you manage queries that return a large number of results:
Cursors, which allow you to resume a long-running query.
Page tokens, which help you paginate the query results.
Limits, which specify how many results to retrieve
Offsets, which allow you to skip a fixed number of documents.
There are no additional costs for using cursors, page tokens, and limits. In fact, these features can help you save money by reading only the documents that you actually need.
However, when you send a query that includes an offset, you are charged a read for each skipped document. For example, if your query uses an offset of 10, and the query returns 1 document, you are charged for 11 reads. Because of this additional cost, you should use cursors instead of offsets whenever possible.
Queries other than document reads
For queries other than document reads, such as a request for a list of collection IDs, you are billed for one document read. If fetching the complete set of results requires more than one request (for example, if you are using pagination), you are billed once per request.
Minimum charge for queries
There is a minimum charge of one document read for each query that you perform, even if the query returns no results.

Do I pay one read when I start listening to a single document in Firestore, even if the doc has not changed?

I know that whenever I turn on a listener to a QUERY, the minimum charge is one read, even if this query returns no documents (because there are no documents that fit the query, or even if there are but there were no changes since last time this listener was on).
According to documentation:
Minimum charge for queries
There is a minimum charge of one document read for each query that you perform, even if the query returns no results.
Stream<QuerySnapshot> stream = Firestore().collection("someCollection").where("someField", isGreaterThan: 42).snapshots();
stream.listen((querySnapshot) => doSomething());
Also, I know that I'm not charged if I use a simple get to read some document, as long as this document already exists in the offline cache,
and was not changed in Firestore (According to Doug Stevenson).
DocumentSnapshot doc = await Firestore().collection("someCollection").document("documentID").get();
My question is:
Suppose a document already exists in my offline cache, and was not changed in Firestore since.
If instead of a get I turn on a listener to this single document
(DocumentSnapshot, NOT a QuerySnapshot), like this:
Stream<DocumentSnapshot> stream = Firestore().collection("someCollection").document("documentID").snapshots();
stream.listen((documentSnapshot) => doSomething());
Will I be charged for one read when this listener is turned on?
Will I be charged for one read when this listener is turned on?
No. If you turn on a listener that is listening to a single document, you are not charged at all since the document already exists in the cache. Remember, you are charged with one document read when a query does not return any results but in your case, you aren't performing any query, you are just listening to a document change. It makes no sense to be charged with one document read each time you start listening for changes or each time you open the application. That's the beauty of Firestore, you have a local copy of your database so you cannot be charged for cached documents, unless the documents are changed in the back-end.

StreamBuilder Controls and Firestore Pricing

I have a two-part question. After reading through Firestore pricing, it says that you are charged based on the number of documents you read and write and the operations you perform such as deleting and some other factors. With that being said, I am using a StreamBuilder that continually refreshes itself whenever the list is scrolled whether there is new data in the database or not. Right now, the builder is fetching from a collection with very little data but that collect can grow to be bigger. With that being said, my questions are:
Each time the StreamBuilder refreshes itself to show new data, is it actually fetching all the documents again from the Firestore collection or is it only looking for changes and updating them? If it is fetching the documents again from Firestore, does Firestore consider this as downloading multiple documents each time it refreshes or does it count it only once and if there are updates to any new document fetched, those are counted separately?
If it fetches all the documents over and over again every 2 seconds or even less as in the current behavior, is there a way to limit this say to every 30 seconds or to when every a RefreshIndicator is used so as to avoid multiple unnecessary reads? I tried using a StreamController but the stream still refreshes every time the list is touched or every second.
Well i guess it depends a bit on your code. I think there are methods to listen to firestore changes constantly.
However if you use the most common queries then this should not be the case. Here my reasoning why, according to my understanding:
Streambuilder: The builder function is triggered everytime data hits the sink of a stream.
Sink is the input channel for any data. Streams immediately return data which is put in the sink.
Firestore: If you execute a firestore "query" it will read document by document and return it once it is read. Once all documents are read the connection will be closed.
If you now assign the firestore query as stream to your builder, example below. The builder is triggered when a document is read. In the builder you then probably build a widget which is displayed.
Once the firestore query has read all documents no new data will be pushed into the sink and therefore the builder will not be triggered anymore. This query will then be completed and no longer listen to changes as the connection will be closed.
Therefore the documents are usually only read once during the lifetime of a streambuilder.
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('your collection').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
//Your own code to handle the data
})
I recently build an app where I read tasks from firestore and process the documents via StreamBuilder. An easy way to test how often a document is read is by simply printing the document to your console in the builder section.
What I observed is that documents are only read once as long as the Widget tree in which the Streambuilder resides is not rebuild.
So to answer your question:
My understanding is that if the StreamBuilder refreshes or is initialized again then it triggers again the query and reads the data. According to the firestore documentation each read of the document is counting towards your limits and costs. So I would say yes it counts for all documents included in your query.
I am not sure how you constantly refresh or initialize the streambuilder, therefore I can't give you a clear answer. If you just use the code similar to above once during the build of the widget tree then it should be read only once...
Without some more details, I cannot provide more information.
Each time the StreamBuilder refreshes, it will query Firestore for the documents in the collection again. Firestore will count this as a read operation for each document retrieved. However, Firestore does not count it as multiple reads for the same document if it is fetched multiple times. Firestore only charges for each document read once.
Firestore provides real-time updates through the use of listeners. When you listen to a Firestore collection using a StreamBuilder, Firestore will automatically send updates whenever there are changes to the documents in the collection. This means that the StreamBuilder will only fetch the documents that have changed, rather than the entire collection. However, if the entire collection changes (e.g. if a new document is added), then Firestore will fetch the entire collection again.
Each time the StreamBuilder refreshes, it creates a new query to Firestore, which counts as a read operation. If you refresh the StreamBuilder frequently, this can lead to a large number of read operations. However, Firestore does not charge you for reading the same document multiple times in a short period of time. For example, if you refresh the StreamBuilder every second and the same document is retrieved each time, Firestore will only count this as one read operation for that document.
To limit the number of reads, you can consider using a caching mechanism to store the data on the client-side and avoid making unnecessary network requests. You can also adjust the frequency of fetching new data by using a timer or a debounce mechanism to avoid refreshing too frequently.

Resources