Editing a Document based on query result in Firestore Transaction - android

I am currently doing a project on Firestore database with Android SDK. I need to write a Transaction, in which I want to edit a "destination" document in "destinations" collection, only when another collection named "batches" does not have any document with its field name "destionId" set to the editing destination document ID. I am checking that with a query with .limit(1) set
Now, I want to do this in a Transaction since this app is real time and will be used by so many people at the same time. If I did not use transaction, then the possibility is that another person may add a "batch" document with this destinationId right between my query for checking and actual editing of the destination document. So, I want to run the query and check batches collection every time the transaction retries.
But I'm not sure how to run the Firestore query inside the transaction as its asynchronous. I believe that there is no way to make a blocking query request in Android SDK. please correct me if wrong.
Can someone help me with an idea of how to resolve this conflict? Thanks in advance.

You can't perform a query inside a transaction, or make a transaction contingent on an unchanging set of query results. You can only fetch individual documents by their ID, with the intent to change them later in that transaction.

In case it's helpful to others, running a transaction that operates on a query result is possible via the admin SDK (in contrast to the Java client-side SDK). Check out the doc on this here.
Retrieve a document or a query result from the database. Holds a pessimistic lock on all returned documents.
This capability is also mentioned in the SO post here. Notice that on the corresponding client-side JS SDK doc, the argument to the get function only accepts a documentRef.

Related

How to handle foreign key kind of situation in google Firestore?

As there is no functionality of foreign Key in Firestore like that of MYSQL, so I am not able to replicate one of my important functionality that is to update a file in one place and it will reflect in every place. Also, Firebase has no functionality to update all the document's specific filed at once.
There are already these kinds of questions but I could not get my solution. Suppose I have a million documents containing a filed which is the density of a material. Later on, I found that my density value was wrong so how to update that value in all documents efficiently. Also, I do not want to use server/admin SDK.
If you need to change the contents of 1 million documents, then you will need to query for those 1 million documents, iterate the results, then update each of those 1 million documents individually.
There is no equivalent of a sql "update where" statement that updates multiple documents in one query. It requires one update per document.
If don't want to use the Admin SDK, then the option that you have is to update the value of your densityMaterial property on the client, which might not be the best solution. However, if you can divide the update operation in smaller chunks, you might succeed.
If you are using a POJO class to map each document, then you might be interested in my answer from the following post:
How to update one field from all documents using POJO in Firestore?
And if you are not using a POJO class, please check my answer from the following post:
Firestore firebase Android search and update query
Regarding the cost, you'll be billed with one write operation for every document that is updated. If all 1 MIL documents will be updated, then you'll be billed with 1 MIL write operations.
Edit:
Suppose I have a million documents containing a filed which is the density of a material. Later on, I found that my density value was wrong so how to update that value in all documents efficiently.
If all of those 1 MIL documents contain a property called densityMaterial, that holds the exact same value, it doesn't make any sense to store that property within each document. You can create a single document that contains that particular value, and in each and every document of those 1 MIL, simply add only a reference to that document. A DocumentReference is a supported data-type. Now, if you need to change that value, it will incur only a single document write.
However, if you have different values for the densityMaterial property and all of them are wrong, then you don't have a problem with the database, you have a problem with the mechanism/people that are adding data. It's not a matter of a database problem if you have added 1 MIL incorrect documents.
Why not chose MySQL?
MySQL cannot scale in the way Cloud Firestore does. Firestore simply scales massively.
Can I avoid this problem anyhow?
Yes, you can buy using a single document for such details.

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.

Firestore document sharing without scanning entire collection

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.

Firestore clients and invoices, amended requirement

This question is a follow up question to the one posted here:
Firestore: Clients and invoices, how to model it
I am trying to understand the thought process behind modelling evolving requirements in Firebase/Firestore.
Assuming the accepted answer was used for the model, then 2 months you get a new requirement after the app has been released. Now the requirement says:
We need to get the invoice detail (not only id but the full details) for user whose last name is xyz.
How can model this assuming the database/app has been live for 2 months (so there is data in there already). The last name is already an attribute of the user details.
Thank you
According to the requirements that we see in this post, which I understand are mandatory in your project:
Show invoices that a client has
and
Update all invoices in the system to false
The most appropriate schema that can I recommend you, is the one in which you should add a new property called userId, beneath each invoice object.
So please consider using this tehnique, which is actually called a the reverse lookup. It will help you query your database more easily and will also help you solve both problems.

How to paging query from Firebase using Android FirebaseUI

I have a chat project using Firebase Android SDK for the server. After 3 months, my application has many users and they chat with each other a lot. It takes a long time to load all of any chat list from Firebase. So now, I wonder that how to paging query from Firebase using Android SDK.
I researched this link to find a query command for this problem but fail. I only query a number of the row from first or last. I could not query from random locate in Firebase. Example using skip and take key to query.
If you have any document about that. Please tell me.
Thanks for advance.
Concepts like skip() or take() don't map well to the realtime world of the Firebase Database. That's why pagination will also be challenging to implement. Technically it is possible, but for a good user experience it's important you keep in mind that the data on a page may change while the user sees it.
Back to how you can implement pagination: the startAt() and endAt() methods take a optional second parameter, which is documented as (emphasis mine):
public Query startAt (String value, String key)
Create a query constrained to only return child nodes with a value greater than or equal to the given value, using the given orderBy directive or priority as default, and additionally only child nodes with a key greater than or equal to the given key.
So if you for example have a list of items sorted by date, you can pass in the date and key of the last item on the previous page to get the next page. You'll have to request one extra item (often called the anchor item), but the overhead should be small.
I tried this demo Firebase Paginator and it work for me. Although, it have some issues.

Categories

Resources