Matching documents in Cloud Firestore (pt. 1) – Firecasts
Articles,  Blog

Matching documents in Cloud Firestore (pt. 1) – Firecasts


DOUG STEVENSON: Hey, gang. Welcome back to the series
on Firebase security rules. Last time, I gave you an
overview of some of the things you can do. This time, we’ll get into
some of the syntax that helps you match objects in
your Cloud Firestore database. Matching documents
is the first step in writing a rule
to protect data when it’s accessed using the
Firebase web and mobile SDKs. The first thing to know is that
every document in your database has a unique path. You’ve probably already
used these paths in your app in order to read
and write documents. This code over here is
building a reference to a document with ID Sparky
in a collection called users. In case you didn’t know, the
name of the Firebase mascot is Sparky. How’s it going
over there, Sparky? Anyway, in terms of
this document’s path, you might think of
it like this string. This is pretty straightforward,
and you can even use this string directly
to build the document reference like this. Now, if you want
to control access to this document
using security rules, you will need to use this path. Let’s take a look at
the required boilerplate for Firestore rules. Here, we have the Cloud
Firestore service identified at the top level,
and nested under that we have a match clause, which
is followed by something that looks like a path. It starts with the
component databases followed by the word database
in curly braces and another
component, documents. What this match
directive is saying is that the stuff
nested inside it is going to be used
to match documents anywhere within your database. The database in curly
braces there is a wild card, and it matches your
project’s database. Currently, there is only
one value that it will match and that’s default
in parentheses, as each project can only
have one Firestore database. But it’s a standard practice
to use a wildcard here. Again, this is all
boilerplate so far. But I’ll nest another
match that calls out the path of the
document to protect, and the nested allow
statement gives everyone read access to it. Now, it’s super
important to note here that all documents
in the database are by default denied
access by security rules when accessed from a
mobile or web client. What security rules let you
do it selectively allow access to documents based on
the criteria you define. Now I find it
unlikely that anyone would need to write a rule
for one particular user’s document, like this. Typically what you
need to do is write rules that apply to
all users in your app, and you typically sign them in
using Firebase authentication. To match all users’ documents
in the user’s collection, you want to use
another wildcard, just like with the
database in the line above. The organization for most
user based collections makes use of the Firebase
authentication user ID as the ID of the document
that belongs to that user. A Firebase authentication user
ID is called a UID for short, so I’ll name the wildcard as
such and put it in curly braces to make it a wildcard match. So now all documents in
the user’s collection are readable by everyone, but
no one can write anything yet. The useful thing
about wildcards is that they become
string variables that you can use
in the expression that you write to allow access. I’ll take advantage
of this to indicate who can specifically
read and write each document in
this collection. So I’ll add another
line here, which says that the only user that
can write the match document is the Firebase Auth
account with the UID that’s the same as the
UID wildcard string value. Now everyone can read
everyone else’s user document, but only the currently
authenticated user can write their own document. I’ll say a lot more
about how authentication works with security
roles in a future video. It’s important to note here
that these wildcards can only match an entire path
segment between the nearest slashes in the path. There are no substring
matches and there are no regular expressions, either. But there is a glob
type of wildcard, which I’ll talk
about later and I will say that you can
perform additional checks against the wildcard variable
string in the allow expression, including regular expressions. But that’s another
topic for another video. Now you might be wondering,
what about subcollections organized under a document ID? Well, let’s say you’re
storing references to photos for each
user and you’ve decided to do that with
a subcollection called photos organized under
each user’s document. You can match those documents
in the subcollection by extending the
match path and adding another wildcard to match
all the documents in each of the user’s photos
subcollection. I’ve removed some
of the boilerplate here to keep things
easier to read. Notice how the user’s
collection– the user document ID, the photo subcollection,
and the photo document ID are all represented in
the match path here. Now, let’s say we only want
people to read and write their own photos for now,
so we’ll add a line here to allow access
on that condition. Notice here that both
read and write access are given with a
single expression. Now here’s one very
important thing to keep in mind about
matching documents. If the path of the
document being accessed doesn’t have a full path
match with the rule, that rule will not apply. So the entire path of the
document– the collection date, the document ID, the
subcollection, and so on– all must be represented
in the match path. Now let’s look at all of the
documents and rules shown so far. The document
referenced by doc ref is only affected
by the first match since it’s not using
the photos collection, and the document
referenced by photo ref is only affected
by the second rule. As you can see, the
photos subcollection is effectively a completely
different collection than users, even though
it’s nested under users. This is not always
obvious at first when you’re getting started
with Cloud Firestore, but the rules here
make that more clear. Using subcollections like
this to change the permissions of various pieces of data that
are associated with the user is a very good practice. You should always
model your data in Cloud Firestore with
security rules in mind. Think carefully
about which users you want to be able to
access which content. There’s a lot to
discuss on this topic, and I’ll cover that
in future videos. But I’ll leave
you with one trick for organizing your rules,
if you choose to use it. If you recall before,
the boilerplate for Firestore security
rules has a top level match for all the documents
in your database and all your document rules
get nested underneath it. Sometimes doing your
own nesting can save you some space and typing. Since the photos
subcollection is effectively nested under documents
in the user’s collection, we can nest the match
for photo documents inside the match for
users, like this. See how the prefix of
users and the wildcard UID are now implied by
the outer match, and you can also use the UID
variable from the outer match just fine in the inner match. Of course, this
nesting is optional, but you might prefer it. Oh, and just one
more little thing– I’ve been using
the word variable to refer to the UID and
photo ID wildcard strings. Well, that’s not
really the best word because these variables
can’t be changed. The values are constant
at the time of evaluation when a specific document
is being read or written. There are no true variables
in security rules. You can only use
their values as is. Before we wrap up here,
take a look at this rule. I’m sure you might recognize it. It’s the rule that
your database probably started with when you
created your project if you chose the initial test
mode for your database. There is an equal star star
in the document wildcard here. This is a special
kind of wildcard, and this rule is actually
matching every single document in your entire database and
granting full read and write access to each of them. This rule is OK to get started
playing around with Firestore in a new app, but if the
rule sounds problematic, that’s because it is. It’s actually very
problematic when it comes time to write effective rules. So when you start writing
rules, first get rid of this one and I’ll say more about why in
the next episode of the series. So stay tuned right here to the
Firebase channel on YouTube, and I’ll see you then. [MUSIC PLAYING]

13 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *