Firestore security rules - can I query for a document with specific fields?
Asked Answered
A

2

13

Can you make security rules that runs a query to check if a matching document is found?

I'm building a system where a logged in user can vote on specific topics.

Every single vote will be saved in its own document, with a reference to the user, the topic etc.

I want to make a security rule that checks if there's already a document in the vote section with that specific user ID and topic ID present, and only let the user write a vote document it that's not the case.

I can't see any query options in the documentation, so what are my options?

Can I somehow create an index of all votes, and look for a specific document path in that index?

Or should I give the votes a custom ID scheme, based on the user ID and the topic ID, so they can be found?

Averyaveryl answered 14/5, 2019 at 18:38 Comment(0)
J
0

For those still interested, this has now changed.

Please see https://firebase.blog/posts/2022/09/announcing-cross-service-security-rules/

You can now use the functions firestore.get() and firestore.exists() to query the database inside Security Rules.

These functions, will however, incur additional reads even if the request is denied.

Joannajoanne answered 20/8, 2023 at 19:54 Comment(3)
While this is helpful to know, it doesn't answer the question. The question was about making a query with a filter in security rules (potentially getting 0 or more documents), not crossing between Firebase products. It's still not possible to make a filtered query in security rules. You can only get a document by ID.Edam
You can see other questions on Stack Overflow that DO ask the question of crossing between services, and have properly updated answers here and here.Edam
Yes, you are correct, I misread the question. One solution for this and for the OP is to create a denormalised list in a known document which can then be queried by field to check if, for example, a certain user has voted on a topic. This file can then be maintained by using Cloud Functions to trigger on the initial create of the vote document.Joannajoanne
E
13

You can't perform a query with conditions with security rules. All you can do is get() a document using its known path. That is to say, you must know all of its collections and document IDs that uniquely identify it.

It sounds like it might be feasible to create others documents (they don't have to contain any data), and their existence can signal the condition you want to protect.

(Yes, sometimes modeling of data has to take security rules into consideration.)

Edam answered 14/5, 2019 at 18:47 Comment(6)
I just had another idea. Since I need to disable voting for all topics where the user has already voted, I was thinking of having a document for each user with a list of all its votes topics. Maybe I could just load the document from and then check if that document contains the topic ID already? something like write if get(/databases/$(database)/documents/users/$(request.auth.uid)/attributes/votes).data[request.resource.data.topic]Averyaveryl
Sure, you can check for a value in an array field in a document.Edam
Great. I guess a numeric array is not the optimal choice here, and an object with the topic IDs as keys, and the value of true would be easier to look up?Averyaveryl
Whichever works for your case. You can use either in security rules.Edam
Do you have an example of finding an element in an array in a document at a specific path, during a security rule evaluation?Averyaveryl
You can use hasAny on the list type document field to determine if it contains some other item. firebase.google.com/docs/reference/rules/rules.List#hasAnyEdam
J
0

For those still interested, this has now changed.

Please see https://firebase.blog/posts/2022/09/announcing-cross-service-security-rules/

You can now use the functions firestore.get() and firestore.exists() to query the database inside Security Rules.

These functions, will however, incur additional reads even if the request is denied.

Joannajoanne answered 20/8, 2023 at 19:54 Comment(3)
While this is helpful to know, it doesn't answer the question. The question was about making a query with a filter in security rules (potentially getting 0 or more documents), not crossing between Firebase products. It's still not possible to make a filtered query in security rules. You can only get a document by ID.Edam
You can see other questions on Stack Overflow that DO ask the question of crossing between services, and have properly updated answers here and here.Edam
Yes, you are correct, I misread the question. One solution for this and for the OP is to create a denormalised list in a known document which can then be queried by field to check if, for example, a certain user has voted on a topic. This file can then be maintained by using Cloud Functions to trigger on the initial create of the vote document.Joannajoanne

© 2022 - 2025 — McMap. All rights reserved.