Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size of firestore rules path

I'm trying to use the size of the path in the firestore rules, but can't get anything to work, and can't find any reference in the firestore docs on how to do this.

I want to use the last collection name as a parameter in the rule, so tried this:

match test/{document=**}
   allow read, write: if document[document.size() - 2] == 'subpath';

But .size() does not seem to work, neither does .length

like image 667
thaffe Avatar asked Oct 17 '22 21:10

thaffe


2 Answers

This can be done but you first have to coerce the Path to a String.

To get the Path of the current resource, you can use the __name__ property.

https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#name

For reference, resource is a general property that is available on every request that represents the Firestore Document being read or written.

https://firebase.google.com/docs/reference/rules/rules.firestore.Resource

resource['__name__']

The value returned by __name__ is a Path, which is lacking in useful methods, so before you can use size you will need to coerce the Path to a String.

https://firebase.google.com/docs/reference/rules/rules.String.html

string(resource['__name__'])

Once converted to a string, you can then split the string on the / operator and convert it into a List of String path parts.

https://firebase.google.com/docs/reference/rules/rules.String.html#split

string(resource['__name__']).split('/')

Now you can retrieve the size of the List using the List's size method.

https://firebase.google.com/docs/reference/rules/rules.List#size

string(resource['__name__']).split('/').size()

One of the challenging things about Firestore rules is that there's no support for variables so you often will repeat code when you need to use a result more than once. For instance, in this case, we need to use the result of the split twice but cannot store it into a variable.

string(resource['__name__']).split('/')[string(resource['__name__']).split('/').size() - 2]

You can DRY this up a bit by making use of functions and using the parameter as your variable.

function getSecondToLastPathPart(pathParts) {
  return pathParts[pathParts.size() - 2];
}

getSecondToLastPathPart(string(resource['__name__']).split('/'))

Tying it all together for your solution, it would look like this...

function getSecondToLastPathPart(pathParts) {
  return pathParts[pathParts.size() - 2];
}

match test/{document=**} {
   allow read, write: if getSecondToLastPathPart(string(resource['__name__']).split('/')) == 'subpath';
}

Hope this helps!

like image 154
Brian Neisler Avatar answered Oct 21 '22 02:10

Brian Neisler


You can learn rules here

   // Allow reads of documents that begin with 'abcdef'
   match /{document} {
      allow read: if document[0:6] == 'abcdef';
   }
like image 29
Bohdan Didukh Avatar answered Oct 21 '22 01:10

Bohdan Didukh