Best practice for storing global app settings in firestore - firebase

I want to know what the best practice is for storing global app settings for your app in firestore. For example if your app has a setting to enable notifications, a setting for what theme color to use, etc. How would you go about structuring your collection and document(s) to make it so you can easily read/write each individual setting.
The method I have tried is creating a Settings Object Model that contains all my apps global settings, then storing and reading the object from Firestore as a single Document - however anytime I want to update a setting I have to retrieve the entire Settings Object from firestore then re-write the entire object back to Firestore after making the change to only a single setting.

The method I have tried is creating a Settings Object Model that contains all my apps global settings, then storing and reading the object from Firestore as a single Document
That's a very convenient way of doing that.
however anytime I want to update a setting I have to retrieve the entire Settings Object from firestore then re-write the entire object back to Firestore after making the change to only a single setting.
There is no need to get the document, in order to make an update. To change the value of a single property, you can simply use call update("propertyName", "newValue") function on your desired document reference.

Related

Restrict specific object key values with authentication in Firestore

I have an object stored in the Firestore database. Among other keys, it has a userId of the user who created it. I now want to store an email address, which is a sensitive piece of info, in the object. However, I only want this email address to be retrieved by the logged in user whose userId is equal to the userId of the object. Is it possible to restrict this using Firebase rules? Or will I need to store that email address in a /private collection under the Firebase object, apply restrictive firebase rules, and then retrieve it using my server?
TL;DR: Firestore document reads are all or nothing. Meaning, you can't retrieve a partial object from Firestore. So there is no feature at rule level that will give you granularity to restrict access to a specific field. Best approach is to create a subcollection with the sensitive fields and apply rules to it.
Taken from the documentation:
Reads in Cloud Firestore are performed at the document level. You either retrieve the full document, or you retrieve nothing. There is no way to retrieve a partial document. It is impossible using security rules alone to prevent users from reading specific fields within a document.
We solved this in two very similar approaches:
As you suggested, you can move your fields to a /private collection and apply rules there. However, this approach caused some issues for us because the /private collection is completely dettached from the original doc. Solving references implied multiple queries and extra calls to FS.
The second option -which is what the Documentation suggests also, and IMHO a bit better- is to use a subcollection. Which is pretty much the same as a collection but it keeps a hierarchical relationship with the parent coll.
From the same docs:
If there are certain fields within a document that you want to keep hidden from some users, the best way would be to put them in a separate document. For instance, you might consider creating a document in a private subcollection
NOTE:
Those Docs also include a good step-by-step on how to create this kind of structure on FS, how to apply rules to them, and how to consume the collections in various languages

Get a custom key generated when pushing to firebase

I am saving some data to firebase, I am using golang admin sdk. My problem is when I push object to firebase it generates an ID which is good for some use cases, but I don't need that what need is a custom integer key like 1,3,4.....
The object may look like this after pushing.
I know I can set it by fetching all data then count them and create next id and add my object under that ID but I don't want this. Is there any way to achieve this in firebase automatically.
You can technically do this but it requires some additional setup.
You will have to maintain the current index in a 'global' position and increment it
there is a risk of write failure if there is a race condition between 2 or more users. to minimize this, you can look at using transactions and rules to control the flow of data.
Additionally, you can use cloud functions to process this if you don't want the client to handle the transaction and updating of the global counter.
Sources:
Cloud Functions
Server side increment
Rules for existing vs new data

When writing to Firestore, how can I know that all triggered have finsihed?

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.

Would storing large chunk of json data in Hooks Context increase server memory usage?

I have read that it is recommended to store data in a store or a context due to the fact that data in the store can be used in any component.
For example in an e-commerce app. I have seen the cart icon which displays the number of items using the Redux Store or Hooks Context to store those numbers and also when click on the cart icon, the items display on the cart page is also using Redux Store or Hooks Context.
My question is using Amazon.com as an example, there are 12 million of products and when users logged out and log in again, they are still able to access to products in their carts. So in this case, is the Redux Store or Hooks Context relevant? And if so, which part? Of course, using Redux Store or Hooks Context to store user profile and authentication is understandable.
Thanks a lot
Your first line essentially answers the question. In order to have persistent cart data it must be stored in a database that has to be read from each time you need it. You save the number of reads by storing it locally.
Without redux you would have to read from the database each time you wanted to know what was in the cart.
With redux you read it once and access it from any component.

How Can I Quickly Populate a Firestore DB?

I'm setting up a Firestore database and am playing around with structuring it. Is there a way to populate and change it quickly without having to add/change fields manually every single time?
Two example things I am looking to do are:
1) Populate collections with documents that have predetermined fields. Currently I have to add the fields manually every single time.
2) Edit the fields en masse for all documents within a collection (e.g. change the name of a field, delete a field entirely, add a new field)
The Firebase console doesn't seem to provide these tools, would my best bet be to write a separate app specifically for this purpose?
Since such bulk uploads and bulk edits are not part of the console, you'll have to build something yourself indeed.
A good place to start would be the Cloud Firestore API, which allows adding and updating documents in the database.

Resources