1
votes

I currently have two arrays in a single document, one representing product ids and the other representing user ids. In my query, I need to query both of the arrays for firestore security rules to work correctly, but to do that, I tried using array-contains and in in the same query, which is acceptable in the documentation, but when I go to query, I get "missing or insufficient permissions".

db.collection('Depots')
  .where("products", "array-contains", productId)
  .where("users", "in", "lk9asdn340fk3fvb")
  .get();

This is my security rule:

function uidAndProductInDocument() {
    return request.auth.uid in resource.data.users;
}

This is what the contents of the document looks like:

enter image description here

However, even this security rule fails and does not return anything, even though there are docs in the database that should be returned, as they match the parameters.

I'm not sure how to secure the product relationship, as that relation for the product-user is in another document, and I have tried another approach in my other question, which can be found here: Firestore security rules: get() use in hasAny() list method

Is there anything that I am missing or need to do for this query to work?

Thanks in advance.

1
Please edit the question to show the exact data in use here. Show us 1) the contents of the document, 2) the full query, and 3) that you're sure a user is signed in. - Doug Stevenson
@DougStevenson I have edited the question for you - I'm certainly sure that the user is logged in for this query, as logging the idToken.claims results in the claims being outputted. Any ideas? Thanks for your help so far. - danwillm
Those values in users don't look like Firebase Auth UIDs. Also, we can't see what's in idToken.claims.user_id. Please edit the question to show all the relevant data, hardcoding values as required, so we can see all the data in play. I've never seen anyone try to use anything but auth.currentUser.uid to specify a UID in a query. - Doug Stevenson
@DougStevenson I've hardcoded the value into the query, which still doesn't work (I changed the actual firebase uids for this question) - danwillm
The value you're passing to the query isn't actually a Firebase Auth user ID, so it doesn't make sense to compare it to request.auth.uid in rules. Actual user IDs are much longer than that. I don't know what that value actually represents or where it comes from, so I don't have any advice on how to proceed. Perhaps you could edit the quesiton to show how you populated that data and what you expect the rule should actually check. - Doug Stevenson

1 Answers

2
votes

You should consider restructuring your data in order to support the query you need. Since Firestore can't perform two array-contains queries, one of your arrays should be converted to an object, where the keys are values of the array, and the field value is simply true. For example, you could take your users list and make it look like this for each user:

users: {
  xxxx: true
  yyyy: true
}

Now you can query like this:

db.collection('Depots')
  .where("products", "array-contains", productId)
  .where(`users.${uid}`, "==", true)
  .get();

And your rule can check like this:

return resource.data.users[request.auth.uid]