I was wondering, how does Firestore handle real-time syncing of deeply nested objects? Specifically, does it only sync the diff?
For example, I have a state of the app which is just an array of 3 values and this state is synced between devices. If I then change one of the values will the whole new array be synced (transmitted on the network) or only the diff? What if my state is the nested object?
I'm asking because I want to sync the whole state which is an object with multiple fields but I don't wont to sync the whole object when I only change single field.
Like Realtime Database, Cloud Firestore uses data synchronization to update data on any connected device. However, it's also designed to make simple, one-time fetch queries efficiently.
Queries are indexed by default: Query performance is proportional to the size of your result set, not your data set.
Cloud Firestore will only send your device only the difference of the document.
Tips:
Add queries to limit the data that your listen operations return and use listeners that only download updates to data.
Place your listeners as far down the path as you can to limit the amount of data they sync. Your listeners should be close to the data you want them to get. Don't listen at the database root, as that results in downloads of your entire database.
Hope it helps!
Related
I am trying to get the changed data only using onchildchanged stream event in flutter, but the problem is it is getting every data under that node which are unchanged.
My Database:
Here if I am streaming rooms node, and try to change the room name ,stream is getting all the data under rooms node ,where I only want the changed node data which is room name in this case.
Flutter code :
Query _userdIdQuery = FirebaseDatabase.instance.reference().child("users").child(FirebaseAuthData.auth.currentUser!.uid).child("rooms").orderByKey();
userIdDataAddSubscription = _userdIdQuery.onChildChanged().listen((event){
print(event.snapshot.value);
});
I can compare the data with my local data in modal class, but I want a efficient/less data consuming method which is avoid getting unchanged data.
Is there any solution to fix it?
Edit: After some research I found that all the data under streaming node will be received when data changes so I think there is no other way to get only changed data.
Currently, I am thinking to stream multiple nodes ,will streaming multiple node impact app performance and network usage?
What you're seeing is the expected behavior. When you subscribe to onChanged on /users/$uid/rooms, you will get called whenever a room changes and you will get a snapshot of the entire room.
The server may send less data to the client than the entire node, but the SDK will always call your code with the complete snapshot of the room. If you want to know exactly what has changed in the room, you'll have to compare the previous data with the new snapshot in your application code.
When using firestore snapshot(), and set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the documents change.
However if I close the app, and reopen it, does firestore make a read on all the data it already has queried or is there an internal sync system (for example if they store documents metadata, like updatedAt they could only read documents that haven't been updated since x) ?
In other words. if I use onSnapshot() listener, I will make x documents read initially, then 1 document each time a document changes. My question is: If I close the app and a document changes, then when I open the app, is 1 read made or x + 1 ?
It is important for me because I have a bunch of initial calls and I'm wondering how that'd affect the cost($).
It's also important to know for data modeling and how it affects the cost.
Every time you perform a new query against the server (this is the default), it will cost a read, and the documents will have to be transferred. It will not use the cache unless there is no connection, or your specifically target the cache for the query. Quitting and returning to the app doesn't change this behavior at all.
I suggest reading this: https://medium.com/firebase-developers/firestore-clients-to-cache-or-not-to-cache-or-both-8f66a239c329
It depends on the type of listener
OnChange() will read only when data changes
addListenerForSingleValueEvent will check just once, and if it is the onCreate section, it will be executed immediately
addValueEventListener will keep checking constantly, but will log as a read only if the data changes
I am using Firestore database with real time updates on web javascript app.
The purpose is to show sensor data (temperature, ultrasonic, etc) for each existent device:
devices/devices01/sensors/sensor01/value:10
devices/devices01/sensors/sensor02/value:15
devices/devices02/sensors/sensor01/value:30
devices/devices03/sensors/sensor01/value:20
The user can have a list of devices it wants to get sensors data real-time updated.
users/userA/devices/{device01:true,device03:true}
users/userB/devices/{device02:true}
I don't know how to query and get the snapshots when:
1. Use device name from a list of devices
2. Get all sensors on change
Of course, this doesn't work:
db.collection("devices").doc("[device01,device03]").collection("pins").doc("*").get()
Any suggestion?
You need to identify each document individually and attach a listener to them all. There are no list-like or wildcard methods to refer to documents.
The only way you can listen to multiple documents at once is when you're able to identify them all with a query. The only kind of query that might help you here is one that identifies all the documents under pins. A CollectionReference is a query that listens to all the documents in that collection.
What is the most performant way of using onSnapshot to listen for changes to a large group of documents in Cloud Firestore?
(There would probably be a max of around 50-75 documents being returned by the query, paged with a 'load more' button which uses query.endBefore)
Would it be better to listen for changes to the entire query, or to query once and attach onSnapshot listeners to each document returned?
Note the documents aren't likely to change THAT often, but I still need to be able to listen for when they do.
You're better off listening to changes to the entire query.
Cloud Firestore is pretty efficient when it comes to sending changes over the network. So if you were to create a snapshot listener for a group of 75 documents and one of them changes, Cloud Firestore will only send your device that one changed document. (You'll still receive the full set of data in your snapshot listener, which is generally what you want. Firebase does the work of merging the new data into your cached data.)
Setting up 75 different snapshot listeners, one for each document, doesn't really save you anything in terms of network or battery costs. (In fact, it probably is less efficient on the client.) But it does make life a lot more difficult for you, and also means you'll miss events like new documents being added to your collection.
Suppose I am creating a transaction app.
How will I store transactions?
I know I need to denormalize.
Would I save the transaction within a transaction node at the first
db level? Or would i save the transaction node under each user's node? Or would i save it in both the transaction node on the first level and the
transaction node under each user's node?
What if the user changed their name, how would I reflect these
changes in both the transaction history of the user and the business?
I feel like the best way is to put it in just the first level of the database and have the user's query the entire list to see their transaction history.
But, If i have a lot of users wouldn't this be extremely slow?
Or is firebase smart enough and fast enough to handle such queries.
Does the user's internet speed affect this querying, especially on a
mobile device?
Can you display the transaction on the screen as it is being loaded?
Would firebase indexing allow me to do these very large dataset queries easily? Perhaps indexing a user's username that is contained inside each transaction?
First, rather than filtering history of transaction data using username I would suggest using userId which will never changed and always unique.
Second, I think saving the transaction globally (without using '/userId') is better. Because :
We need to able to summarize all transactions for accounting reason
If you think the query will be slow even after using index, you can consider loading part of query result using limitToFirst() just like pagination in web (infinite scroll in android). There is great tutorial here