Search code examples
firebasegoogle-cloud-firestorefirebase-security

Firestore Security Rules: How to perform a collection query within firestore rules?


My database structure is as follows:

/sites/{siteId}/pages/{pageId}

now I don't want to allow update the isPublished field of a page if there are already 3 published pages in the pages collection.

For this I would need to query the pages collection with "isPublished", "==", true filter and check the amount of docs.

Is there a way in firestore security rules to achieve this

match /sites/{siteId}/pages/{pageId} {
 
   allow update: if request.resource.data.isPublished == true ? canPublishPage(siteId) : true 

}


function canPublishPage(siteId) {

   // how can I check number of published page at the moment?

}

Solution

  • There is no way to calculate this kind of aggregate data from the rules.

    Instead you will have to:

    1. Add a counter within the siteId document, incremented at each page creation. You will want to use a batch here to update the site counter and create the page both in an atomic way. Use the getAfter function in your rules for pageId to verify the counter is properly incremented:

      function isCounterIncremented(siteId) {
        let counterbefore = get(/databases/$(database)/documents/sites/$(siteId)).data.counter;
        let counterafter = getAfter(/databases/$(database)/documents/sites/$(siteId)).data.counter;
        return counterafter == counterbefore + 1
      }
      
    2. Check that counter from the rules when a page is updated using get in your rules:

      function canPublishPage(siteId) {
        return get(/databases/$(database)/documents/sites/$(siteId)).data.counter < 3;    
      }