I have a social networking structure in my Firebase Database that provides a user following system
user-followers
-F2iRZkwfuTcKUvd7uYD0jwWeJ7T2
-KgkkWy5xesvcFcL9GMh:
-username: 'billybob'
-fullName: 'Billy Robertson'
-KgkoZpD0GP687J_5Zh5: true
-username: 'coolguy55'
-fullName: 'Jim Davis'
This works fine for reading a summarized view of a given user's followers. However, when a user updates their profile, say their username or fullName, the data under user-followers immediately becomes outdated.
Is there any feasible solution to keeping this nested data updated, without writing an extra function when a user's profile is updated? To me this seems unavoidable
Any input is appreciated!
You could use Cloud Functions for Firebase to write a database trigger that runs in response to writes that happen in one place in your database so that other changes can be made to keep things consistent where data needs to be duplicated.
Related
Background: I am using Firestore as the main database for my (web) application. I also pre-render the data stored in there, which basically means that I collect all data needed for specific requests so I can later fetch them in a single read access, and I store that pre-rendered data in a separate Firestore collection.
When a user changes some data, I want to know when this background rendering is finished, so I can then show updated data. Until rendering is finished, I want to show a loading indicator ("spinner") so the user knows that what he is currently looking at is outdated data.
Until now, I planned to have the application write the changed data into the database and use a cloud funtion to propagate the changed data to the collection of pre-rendered data. This poses a problem because the writing application only knows when the original write access is finished, but not when the re-rendering is finished, so it doesn't know when to update its views. I can hook into the table of rendered views to get an update when the rendering finished, but that callback won't be notified if nothing visibly changes, so I still do not know when to remove the spinner.
My second idea was to have the renderer function publish to a pubsub topic, but this fails because if the user's requests happens to leave the original data unchanged, the onUpdate/renderer is not called, so nothing gets published on the pubsub and again the client does not know when to remove the spinner.
In both cases, I could theoretically first fetch the data and look if something changed, but I feel that this too easily introduces subtle bugs.
My final idea was to disallow direct writes to the database and have all write actions be performed through cloud functions instead, that is, more like a classical backend. These functions could then run the renderer and only send a response (or publish to a pubsub) when the renderer is finished. But this has two new problems: First, these functions have full write access to the whole database and I'm back to checking the user's permissions manually like in a classical backend, not being able to make use of Firestore's rules for permissions. Second, in this approach the renderer won't get before/after snapshots automatically like it would get for onUpdate, so I'm back to fetching each record before updating so the renderer knows what changed and won't re-render huge parts of the database that were not actually affected at all.
Ideally, what (I think) I need is either
(1) a way to know when a write access to the database has finished including the onUpdate trigger, or
(2) a way to have onUpdate called for a write access that didn't actually change the database (all updated fields were updated to the values they already contained).
Is there any way to do this in Firestore / cloud functions?
You could increment a counter in the rendered documents, in such a way a field always changes even if there is no change for the "meaningful" fields
For that, the best is to use FieldValue.increment.
So I have a Firestore database where i have all my posts in, I push them on page load into the store so I can have a fast navigation and only need to fetch once.
What I wanna do now is to use a persisted state so i dont need to refetch it if the user opens a new window or F5(reloads) the page.
The problem is im not sure how to check if new Posts are in the Firestore without querying all posts and I havent found any methods to do it in a healthy and Read efficient way.
There's no super easy way around it - at the end you have some data, and the server has another, you need to check for differences.
If you're only trying to figure out if there are new posts on the backend, which are not loaded on your frontend, then just get the date on your last post, and then ask Firebase for all posts after this date :)
Of course if you don't have posts, ask for everything.
Keep in mind you need to manually check if posts are deleted ;)
Realtime updates with the onSnapshot method can be used to keep local data in sync with the server. If you initially load it into vuex then subsequent changes on server side will be reflected automatically.
https://firebase.google.com/docs/firestore/query-data/listen
To share one set of data across tabs/windows you could look at something like this
https://github.com/xanf/vuex-shared-mutations
I am trying to figure out the best way to execute my cloud function for my firestore database, when data is being read.
I have a field on all of my documents with the timestamp of when the document was last used, this is used to delete documents that haven't been used in two days. The deletion is done by another cloud function.
I want to update this field, when the documents is being used AKA read from my db. What would be the best way to do this?
onWrite(), onCreate(), onUpdate() and onDelete() is not an option.
My database is used by a Android App written in Kotlin.
There are no triggers for reading data. That would not be scalable to provide. If you require a last read time, you will have to control access to your database via some middleware component that you write, and have all readers query that instead. It will be responsible for writing the last read time back to the database.
Bear in mind that Firestore documents can only be written about once every second, so if you have a lot of access to a document, you may lose data.
If I have User and Profile objects. What is the best way to structure my collections in firestore given that the follow scenarios can take place?
Users have a single Profile
Users can update their Profile
Users can save other users' profiles
Users can deleted their saved profiles
The same profile can't be saved twice
If Users and Profiles are separate collections, what is the best way to store saved profiles?
One way that came to mind was that each user has a sub collection called SavedProfiles. The id of each document is the id of the profile. Each saved Profile only contains a reference to the user who's profile it belongs to.
The other option was to do the same thing but store the whole profile of each saved profile.
The benefits of the first approach is that when a user updates their own profile there's no need to update any of the their profiles that have already been saved as it's only the reference that is stored. However, attempting to read a user's saved profiles may require two read operations (which will be quite often), one to get all the references then querying for all the profiles with those reference (if that's even possible???). This seems quite expensive.
The second approach seems like the right way to go as it solves the problem of reading all the saved profiles. But updating multiple saved profiles seems like an issue as each user's saved profiles may be unique. I understand that it's possible to do a batch update but will it be necessary to query each user in the db for their saved profiles and check if that updated profile exists, if so update it? I'm not too sure which way to go. I'm not super used to NoSQL data structures and it already seems like I've done something wrong since I've used a sub collection since it's advised to keep everything as denormalized as possible so please let me know if the structure to my whole db is wrong too, which is also quite possible...
Please provide some examples of how to get and update profiles/saved profiles.
Thank you.
Welcome to the conundrum that is designing a NoSQL database. There is no right or wrong answer, here. It's whatever works best for you.
As you have identified, querying will be much easier with your second option. You can easily create a Cloud Function which updates any profiles which have been modified.
Your first option will require multiple gets to the database. It really depends how you plan to scale this and how quick you want your app to run.
Option 1 will be a slow user experience, while all of the data is fetched. Option 2 will be a much faster user experience, but will requre your Cloud Function to update every saved profile. However, this is a background task so wouldn't matter if it takes a few seconds.
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