Rajarshi
Rajarshi

Reputation: 2509

Firestore create document if it doesn't exist security rule

I was trying to write a rule that if the id of the document doesn't exist, then create a new document. My object is:

Message message = new Message(userId, title, messageBody, timestamp);

and I'm using WriteBatch to create a new document and updating the same:

mWriteBatch.set(mMessageRef.document(messageId), message);

mWriteBatch.update(mMessageRef.document(mIntentMessageId), // params...);

After browsing through the docs and this site I've found out that if I use create method, it only allows to write the data if it doesn't exist.

So I created a security rule like:

match /messages/{message} {
  allow read; 
  allow create: if isSignedIn();
  allow update, delete: if isSignedIn();
}

isSignedIn() is just a method contianing request.auth != null. This rule fails and overwrites the data. Now I tried:

match /messages/{message} {
  allow read; 
  allow create: if request.resource.id != message;
  allow update, delete: if isSignedIn();
}

This time also it overwrites the data instead of showing an error.

What am I doing wrong here? Any help is appreciated.

Update: As told by José David Aroesti in the comments, I have to change it to exists and remove update and delete to work properly and from the app it's reflecting what it's suppose to do. But then how would I update and delete a document?

For example, when I'm using the below rules in Simulator, both are being executed as expected but when I'm testing it from the device, I'm always able to create a document even if it exists:

allow create: if !exists(/databases/$(database)/documents/messages/$(message));

allow update: if get(/databases/$(database)/documents/messages/$(message)).data.timestamp
        < request.resource.data.timestamp;

Is it possible?

Upvotes: 2

Views: 2859

Answers (1)

David Aroesti
David Aroesti

Reputation: 626

You can use the exists() and get() built-in functions to verify if the document exists or to access the document so you can read its data.

In this case, an example would be:

match /messages/{message} {
    allow read; 
    allow create: if !exists(/databases/$(database)/documents/messages/$(request.resource.id));
}

And as @creativecreatorormaybenot suggested, you should not specify allow expressions for update and delete so the data cannot be overwritten.

Here is a link to the documentation:

https://firebase.google.com/docs/firestore/security/rules-conditions#access_other_documents

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

Upvotes: 7

Related Questions