Firestore document sharing without scanning entire collection - android

I am learning my basics for Firestore and trying to build an app which allows user1 to share a document with user2/3/4 etc.
For billing purposes, every query which results in a document read counts towards the cost. So, I do not want to follow the approach of adding the user2/3/4 etc emails to a 'sharedWith' variable to type: array or map type structure as I believe every user will then have to scan the entire collection and pick the documents where their email appears.
Is there any other approach to this where user1 can programmatically give access to user2/3/4 of one specific document?

For billing purposes, every query which results in a document read counts towards the cost.
That's correct and according to the official documentation regarding Cloud Firestore billing:
There is a minimum charge of one document read for each query that you perform, even if the query returns no results.
So you're also charged with one document read, even if your query does not return any results.
I believe every user will then have to scan the entire collection and pick the documents where there email appears.
That's also correct. So let's assume the email address that you are looking for exist in a document that is appart of 10k collection of documents. So if you query the database only for that particular document, you'll be charged with only one document read and not for those 10k. So you are charged according to the number of items you get back and not to the number of items your request them from. And this is available for the first request, when you get the data from the Firebase servers. If in the meanwhile nothing has changed, second time you get the data from the cache since Firestore has the offline persistence enabled by default. Which means you aren't charged for any other document reads.
Is there any other approach to this where user1 can programatically give access to user2/3/4 of one specific document?
Without writing the data to database, there is not. So you should add the ids or email addresses to the desired documents and perfom a query according to it.

Related

Firebase: is it overall better to store the uid of a user as the doc ID for the Users collection?

I have a Firestore collection called users that stores all my user info. When registering a new user, I first register them with Firebase Auth, then create the record in the users collection. Right now I'm storing the UID as a field, which means when I want to query a user's info, I need to do a query with a WHERE clause. However, one alternative to faster querying would be to store the UID as the document ID for the collection. That would make it so that I could query the collection with a specific ID, which intuitively seems faster.
Using the UID as the doc ID makes me worried about some stuff:
I'm not sure if I can assume that uniqueness for the UID in Firebase Auth implies uniqueness when using it as the doc ID in a Firestore collection.
I watched a tutorial video by Todd that said that querying is faster if you use the auto-generated document ID that Firestore provides. Given this, I wouldn't want to take a risk using something else when the provided doc ID is known to be faster for querying.
What would be the better approach to make querying as efficient as possible, assuming you are querying only based on UID? Or is the difference so negligible that this is a moot point?
yes, that is the most recommended approach because firebase auth ensures that your users have a unique id so no need to worry about duplicates. Another thing is storing separate id other than the uid is redundant because what you'll need most of the time in your app is the user uid to make sure that the auth user and the stored user are one and only the same person.
If the uid in Firebase Auth is unique, and you're building the users collection based on the uid from Firebase Auth, then it follows that the uids which will populate the users collection will also be unique.
The only way this wouldn't be the case is if you're going to be mixing manually generated entries into the users collection with your own uids that aren't following Firebase Auth's generation procedures.
I did a mini project like this earlier this year that pretty much did exactly this (users sign-in with google, uid gets added to the users collection, and then their data gets stored under their uid in the collection). It wasn't a commercial product and my userbase was fairly small, but I didn't observe any reason for concern at the time.
Re: speed, I'm not sure what the impact is, but I would expect it to be negligible enough to call it moot. Querying a collection is basically just searching a list/array for a value, and most backends tend to handle a basic operation like that pretty efficiently.
I'm not sure if I can assume that uniqueness for the UID in Firebase Auth implies uniqueness when using it as the doc ID in a Firestore collection.
The document IDs that are generated by Firestore are completely random. So there is nothing to worry about.
I watched a tutorial video by Todd that said that querying is faster if you use the auto-generated document ID that Firestore provides. Given this, I wouldn't want to take a risk using something else when the provided doc ID is known to be faster for querying.
When only need to read a single document, for instance, the user document, it's always recommended to create a document reference that points to that document rather than performing a query. A query basically means that it needs to evaluate all records in order to provide an result.
And using the UID as a document ID is a quite common practice.

Firestore Database Structuring

I am building a social app that lets users add posts based on the country code. For main feed, I will fetch posts of every country posts based on timestamp. For example, if you are in Turkey, only posts within Turkey will show up in your feed. There is no follower/ following system.
Should I store all posts in one posts collection with the country code field? Or it is more flexible to group them as posts/countryCode/posts. I just don't know if firestore is powerful enough to query all posts for specific country code and timestamp.
What is the best approach for flexibility and pricing?
For only what you're describing here, it actually doesn't matter at all what you choose.
Pricing is based on the number of documents read in a query. That's not going to change in either case.
If all you want to do is query by country code, it doesn't matter if you put everything in one collection, or use subcollections with a collection group query. As long as the country code is a field in the document, either way, you will be able to filter for only that code.
Choose whatever one you are more comfortable with.

How to automatically delete firestore documents which are created before N days?

I have data structure like this:
Employees (Collection) > {EmployeeID} (Documents) > Chat (Collection) > {ChatId} (Documents).
In chat collection each document having 3 fields. 1. senderName, 2. sendTimestamp, 3. messageText.
I want to delete chats which are older than 7 days (from today).
I think it might be possible through cloud function but I am really basic user and don't know much about cloud functions. Please note that I don't want to make it automatically (cron job). I will do it manually on daily basis or whenever I wish.
I really searched a lot for this but its really hard. Please help me.
A big part of this task involves querying a sub collection. You can read more about this idea here: Firestore query subcollections
There are basically two options at the time of writing this:
Query the entire top level collection (Employees) something like db.collection('Employees').get(). Then you would have to loop through each employ object querying for their sub collection (Chat) based on their date range. Firestore query by date range for more reading on querying by a date in firestore. This could result in a large amount of reads depending on the number of Employee documents, but is the "easiest" approach in terms of not having to make changes to your data models/application.
Restructure your data to make the sub collection Chat a top level collection. Then you can do a query on this top level collection by the date. Less reads, but may not be as feasible depending on if this app is in production/willingness to make code changes.
A Function would definitely be able to accomplish this task either way you decide to approach it. One thing to note is that a Function executes using the Admin SDK, meaning it can basically ignore security rules set up on your Firestore.

QuizApp - Firebase/ FireStore Reads

I want to make an online QuizGame using Android Studio and Firebase.
First step will be a game mode for one Player where he gets Questions from the server. The code itself is not a big problem but I have a question about the reads/pricing of Firestore.
The gameplay will look like this: One Round, 5 questions. I want to make a Database looking like this:
Project: Category(Collection) -> generatedID(Document) -> custom Object (My custom Object has an Arraylist of Question, Correct AnswerA, AnswerB, C and D).
My general question is, lets say I am looking for an ID. I have for example 50 IDs in my Category Collection. If I start a query it will check every entry if the saved ID == my searched ID. Will that be a total of 50 reads or only one?
Firestore pricing is based on document reads, writes and deletes. If you run a query, you will be charged for any documents returned by that query, not the total number of documents in the collection. You can avoid un-necessary cost by the use of cursors and pagination, if you need to return large datasets. If you are only searching for a single ID, then it is likely that'll only return one document and, therefore, it'll only cost you for one document read.
If your query returns no results, you will be charged for one document read.
You can get more details from the Cloud Firestore pricing page

Firebase Query: equalTo on a list

We are building an android app that needs to synchronize phone contacts with people already registered on the app. We are using firebase
To do this, we'd like to retrieve a list of existing users based on their phone numbers.
I have managed to retrieve users based on their phone number with ref.orderByChild("phone").equalTo($phoneNumber)
But I am wondering if there is a way of passing a list of phone numbers, instead of querying for each phone number one at a time ?
Something like this:
ref.orderByChild("phone").isIn([phone1, phone2, phone3])
I am just beginning to learn Firebase but I love the concept :)
Thanks a lot for your answers!
Firebase doesn't have or or in operators on its queries.
The closest you can come with with the startAt and endAt functions, to select a range. But that doesn't work for your use-case.
Normally when people are asking for this type of operation, there is a relation between all the pieces that they're trying to combine in a query. For example in your case, the use-case is likely something like: "get the name for all contacts in the user's address book".
In such a situation there are a few options:
monitor each contact with a separate query
embed the necessary metadata for each contact into the user's address book
Option 2 is the cheapest way to get the information, because you only need to read the address book. But it comes at the cost of data duplication, which more relationally trained developers are unused to. See this answer for a coughgreatcough example of such denormalization: Firebase data structure and url
Option 1 is not nearly as expensive as you may expect, since Firebase will open a socket connection only once and then perform all additional queries over that same connection.

Categories

Resources