How much i pay when use onSnapshot firestore? - firebase

So when i read realtime data use onSnapshot in collection with 1000 document, i will pay for 1000 read for first time i render the page.
Nah my question is, when someone add 1 new document to that collection, am i get charged only for read 1 new document or i get charged again for read 1000 document + 1 new document ?
I read some post on this site about that, and also i read from firebase website in link below but i not really understand.
https://firebase.google.com/docs/firestore/pricing#listens
This post
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.

My question is: when someone adds 1 new document to that collection, am I get charged only for read 1 new document or I get
charged again for read 1000 document + 1 new document ?
The answer is to be found in the second paragraph of the documentation excerpt you mention in your question:
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.
Listening to an entire collection is totally equivalent to listening to a query (the CollectionReference class extends the Query class), therefore when someone adds a new document to the collection, you are charged only for one document read.

Related

Nested snapshot listeners

I use Google Firestore for my iOS app built in Swift/SwiftUI and would like to implement the Snapshot listeners feature to my app.
I want to list all documents in debts collection in realtime by using snapshot listeners. Every document in this collection has subcollection debtors, which I want to get in realtime for each debts document as well. Each document in debtors has field userId, which refers to DocumentID in users collection which I would also love to have realtime connection on (for example when user changes his name I would love to see it instantly in the debt entity inside the list). This means I must initialize 2 more snapshot listeners for each document in debts collection. I'm concerned that this is too many opened connections once I have like 100 debts in the list. I can't come up with no idea apart from doing just one time fetches.
Have anyone of you ever dealt with this kind of nested snapshot listeners? Do I have a reason to worry?
This is my Firestore db
Debts
document
- description
- ...
- debtors (subcollection)
- userId
- amount
- ...
Users
document
- name
- profileImage
- email
I uploaded this gist where you can see how I operate with Firestore right now.
https://gist.github.com/michalpuchmertl/6a205a66643c664c46681dc237e0fb5d
If you want to read all debtors documents anywhere in the database with a given value for userId, you can use a collection group query to do so.
In Swift that'd look like:
db.collectionGroup("debtors").whereField("userId", isEqualTo: "uidOfTheUser").getDocuments { (snapshot, error) in
// ...
}
This will read from any collection name debtors. You'll have to add the index for this yourself, and set up the proper security rules. Both of those are documented in the link I included above.

Do Observables re-query ALL data when Firestore fields update?

Let's say I do a query against a Firestore collection over a date range or something. If I get an observable to the set of documents and iterate through it to build up a local collection, will it re-read all the data from Firestore every time there is a change in Firestore? Say this observable is from a where clause that contains 500 documents and I iterate through doing something:
this.firestoreObservable$.subscribe(documents => {
documents.forEach(async doc => {
// do something
})
})
If one field on one documents change on Firestore, will that count as another 500 document reads? If so (ouch!) what would the recommenced best practice be to keep from spending so many reads?
Thanks.
No. If only one document changes, then it will cost only one read. The entire set of documents is cached in memory as long as the query is actively listening to updates, and the SDK will deliver you the cached results in addition to whatever actually changed.
If the query ends and a new one starts up, then you will be charged for the full set of results again.

Firebase Firestore Documents changes history (like Activity log/ History for changes in each Doc)

I'm trying to make an Activity log system or history for my docs, so every time a field is modified in a document i want to record or save that so i can see after changes history made on each document.
how i can achieve that ? i don't want to save the full doc on each change and then have tons of duplicated docs, if possible i just want to get the changed field (ex. name: 'john' -> name: 'jack').
i don't want to save the full doc on each change and then have tons of duplicated docs
Once a document has changed it becomes a new document. So you won't have duplicate documents unless you make changes that were previously made. Please also note that in Cloud Firestore there are no field-level permissions or access to a document. It's the entire document, or nothing. So if you want to change a field within a document for example from:
userName = "John"
into
userName = "Jack"
You'll will get the entire document and not only the userName property that has been changed.
Cloud Firestore listeners fire on the document level. There is no way to get triggered with just particular fields in a document.
If you want to get notified only of specific fields, consider adding an extra collection with documents that only contain those fields. This sort of data duplication is quite common in NoSQL solutions such as Firestore and for that, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase real-time database but same principles apply to Cloud Firestore.
For a database schema you can also take a look at my answer from this post.
The best way to achieve something like this is to store the before and after changes happening to the doc, in a new document, which you can add in a subcollection. The changes are available with cloud functions onUpdate trigger. I have written in depth about this topic on my blog, have a look.
https://blog.emad.in/audit-logs-for-firestore-documents/
You can obtain this by creating a cloud function that triggers on all document updates in all collections:
--trigger-resource=projects/$PROJECT_ID/databases/(default)/documents/{collection_id}/{document_id}
In the cloud function you can obtain all the updated fields and their values through the data object.
Python example:
def main(data, context):
# Extract resource
resource = context.resource
resource_split = resource.split('/')
collection_name = resource_split[-2]
document_id = resource_split[-1]
# Get old fields
data_old_values = data['oldValue']
data_old_values_fields = data_old_values['fields']
# Get updated fields
data_updated_mask = data['updateMask']
data_updated_fields = data_updated_mask['fieldPaths']
# Get new field values
data_new_values = data['value']
data_new_values_fields = data_new_values['fields']
# `data_updated_fields` is a list of the fields that has been changed
# `data_old_values_fields` is a dictionary with the old values of the document
# `data_new_values_fields` is a dictionary with the new values of the document

Firestore onSnapshot - how to tell which individual fields changed?

I’m modeling data and have a question about the onSnapshot (web) listener. As pointed out in a couple posts on SO and in the docs, after the initial invocation, the listener only fetches the changed data. I am interested to know what the changed data is. If listening on a document, is it just the field or the entire document that is fetched?
In a scenario where we have a listener on a Document, and the value of a field on that document changes (or a field is added, or removed), is only that field is fetched? In other words, is this similar to placing a child_changed/added/removed listener on a node in the RTDB?
The intent is to determine if I should keep frequently changing Documents, which clients must listen to, in RTDB or Firestore. I prefer not to resend the entire document to the client due to only a field change, if possible.
Example. We have the following document:
rando_id:
field1
field2
field3
If field2's value changes, will only field2 be the transmitted data from Firestore DB to the client? The same would apply to adding a field4 or removing field1. Would just those fields be sent to the client?
The unit of storage in Firestore is the document. There are no more granular ways to transmit data. There is no API to tell what exactly has changed in a document - you would have to determine that yourself using a prior snapshot, if available. You also can't target document fields in security rules. With documents in Firestore, it's either all or nothing.

Firebase - Firestore - how many time will I read documents

With the new Firestore from Firebase, I discovered that I have poor knowledge with Observables.
My problem is the following:
I get some data with db.collection('room').
If I don't listen to the observable with a subscription, do I fetch the document? (I think so).
For every change in my collection "room", is it considered as a "new document read" by Firestore?
If I have duplicated Observables which return db.collection('room') in my app, will I have X calls to the Firestore database or just one?
Thanks!
If I don't listen to the observable with a subscription, do I fetch the document? (I think so).
When you call var ref = db.collection('room'), ref is not really an observable it is a reference to the 'room' collection. Creating this reference does not perform any data reads (from network or disk).
When you call ref.get() or ref.onSnapshot() then you are fetching the documents from the server.
For every change in my collection "room", is it considered as a "new document read" by Firestore?
If you are listening to the whole collection (no where() or .orderBy() clauses) and you have an active onSnapshot() listener then yes, you will be charged for a document read operation each time a new document is added, changed, or deleted in the collection.
If I have duplicated Observables which return db.collection('room') in my app, will I have X calls to the Firestore database or just one?
If you are listening to the same Cloud Firestore data in two places you will only make one call to the server and be charged for the read operations one time. There's no cost/performance penalty to attaching multiple listeners to one reference.

Resources