Firebase Firestore prevent client side creation of fields in a document - android

I am struggling to find a solution to prevent clients from just creating random fields with values in a document where they have write access to in Firestore. Since you cannot restrict access to single fields in Firestore like you could with the realtime database, this seems hard to achieve.
A solution would maybe be to not allow creation of fields and just letting clients update fields, but this would mean you would have to precreate the fields for documents which is not really a good solution in my opinion, especially if you have documents per user, which are dynamically created and having to use cloud functions to precreate fields in a document just seems unjustified.
Does anyone have a better solution?

As said in the Firebase Firestore documentation, you actually can prevent or allow writes or reads in certain fields. This can be achieved by adding a rule similar to this:
match /collection/{doc} {
allow update: if request.resource.data.field == resource.data.field;
}
Which would basically check if that specific field will have the exact same value after the update. You can also add rules to check if the requested value is between a range or equals to (your predefined value).
allow update: if request.resource.data.field > 0 && request.resource.data.field > 100;

You can inspect the keys of the request.resource and only have it pass if it doesn't contain a field that you want to keep read-only (meaning that the request isn't trying to update that field). For example:
allow update: if !request.resource.data.keys().hasAny(['my_field'])
(Thanks to James Qualls for the inspiration!)

Related

Running a nested query in Cloud Firebase?

I'm messing around with Cloud Firestore. Trying to decide whether I should use it for my next project.
I would like to make a nested query, but all the tutorials and examples I found in the official documentation only query objects which are 2 levels deep and most of the time direct key/id calling.
I need something which is I believe called "nested query" I may be wrong on that one though, maybe it is not the correct phrase for such a thing in NoSQL which I just started to learn.
This is a skeleton/pilot app for a game where users can create characters. and I would like to query whether a character's name is already taken or not.
Here is my simple DB structure:
The main collection is named "users"
In "users" I have user documents.
In each user document, I have a collection named "characters"
In "characters" I have character documents.
In each character document there are two fields, name and level.
I tried it various ways with queries and the closest thing I could get was iterating through the whole thing which I believe is not the perfect solution.
Can somebody please help me to write an efficient nested query whether "Example Name" is already an existing character in the DB and tell me what is the correct way when you want to write like "infinitely deep" nested queries?
If each user document contains a sub-collection that has the same ("characters") name, then I think you are looking for a collection group query. So a query should look like this:
val queryByName = db.collectionGroup("characters").whereEqualTo("name", "Adam");
Don't also forget to create an index.
Besides that, Firestore is as fast as it is at level 1 is also at level 100. So no worries.

How to give data access in cloud firestore to another added users in android?

I wanna ask about the concept and logically ways to give another user the privilege to access other's users' data. What I want to do exactly is like this :
Basically, collection 1 contains several Users ID (UID) from authentication, then the user will have their own data collected in collection 2 which contain the data ID.
So, it's like giving access to another user to collaborate with the data like Google Docs Apps where we can add another user to edit our documents. I've been thinking of how to do this, but still, I got stuck.
My question is, how can I possibly do this? cause from what I've read, cloud firestore don't use such a foreign key like MySQL. Thank You
haven't tried something like this but i think this approch overcomes your problem.
modify your structure according to above image. userID collection will contain userIds which are allowed to edit their parent collection.and create firestore rules according to your use to check weather the userId is allowed to edit the Collection or not.
in your case when 'user 2' will have reference to 'collection 2', he/she will try to change data. firebase rule will check if auth.userId is inside the 'collection2.UserIDs' or not and will allow according that.

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 obtain documents based off comparing two fields Firestore

I am currently trying to write an app for an inventory management system and got a little stuck with one particular feature. I want to app to report to the user what stock is currently low in stock (upon request). I therefore added another field to be used in my product collection in firestore whereby the user can specify a minimum quantity on hand count. I want to know if it possible to obtain all the documents where (in my case) the current stock level is less than or equal to minimum stock level. In this case I have a single collection containing documents for each product, with each document containing various fields including the minquantity and currentquantity fields.
My only solution that I currently have is to obtain all the documents in the product collection and loop through every single one of them, but I am trying to improve the time it takes by minimizing the number of documents obtained.
There is no way to query Firestore in the way you want, you can't use a reference to a field in the value of a condition.
As usual when it comes to NoSQL databases, the solution is to add additional data to your data model to allow the use-case. In this case, consider adding a quantitityBeforeNeedToReorder field (there is probably a more concise name than that) and update that whenever you update the currentQuantityField too. With that field in place, your query is possible and quite simple.
You can even in security rules ensure that this quantitityBeforeNeedToReorder field has the correct value, as (unlike in queries) the security rules can do basic math between fields.

Prevent users from manipulating firestore data

I have an android app which uses firebase for authentication and firestore for storing user data. Once the authentication is complete for a first time user, we collect extra info like nick name, age etc and store them in Firestore. We also have an important field called USER_BALANCE. This is set to 0 on new account creation. How can i make sure they dont manipulate this field.
int USER_BALANCE = 0;
User user = new User(name, email, USER_BALANCE,0,0, refreshedToken); db.collection(FIREBASE_COLLECTION_USERS).document(firebaseUser.getUid()).set(user).addOnSuccessListener(this);
We also have certain task in app,on completion where user gets rewarded and points will be added to USER_BALANCE in firestore. I want to make sure nobody decompile the app and can update the field with whatever value they want.
You can use firebase rules for that. Firebase rules check if a user is able to manipulate your data. You can choose for the user to be able to only read the specific value. Because you haven't provided a view of your database structure I haven't tell you how the specific rule that you need will be framed. Check this blog it really helped me a lot when I was starting.
---Edit---
The below firebase rule checks if the user tries to update the specific field and blocks it. You can check this post for more information.
function notUpdating(field) {
return !(field in request.resource.data)
|| resource.data[field] == request.resource.data[field]
}
match /Users/{userId}{
allow read;
allow update: notUpdating('user_balance');
}
Anybody can decompile the app and attempt to make changes. There is no way to prevent that. They don't even need your app to write the database, since it has a public REST API.
What you will need to do instead is use Firebase Authentication along with security rules to determine who can read and write which documents. There is no other way to control access to your database if you intend for your app to be able to read and write it directly. If you can certainly disable public access entirely and create your own backend - but you have just shifted the responsibility onto the backend for making sure the API it exposes also does not allow arbitrary callers to make unauthorized changes.

Categories

Resources