skip to Main Content

In my code I’m updating a user’s "decks" list by adding one item:

const deckId = 'fake-deck-id';
await updateDoc(doc(db, 'users', userId), {
  decks: arrayUnion(deckId),
});

However, this is giving a permission-denied error. Here are my firestore rules:

  // Allow updates only to the "decks" and "votes" lists
  allow update: if request.auth != null &&
  request.auth.uid == userId &&
  (
  (
  // Allow updates to "decks" using array operations
  request.resource.data.keys().hasOnly(['decks']) &&
  request.resource.data.decks is list &&
  request.resource.data.decks.size() == resource.data.decks.size() + 1
  ) ||
  (
  // Allow updates to "votes" using array operations
  request.resource.data.keys().hasOnly(['votes']) &&
  request.resource.data.votes is list &&
  request.resource.data.votes.size() == resource.data.votes.size() + 1
  )
  );

I can’t figure out why this isn’t working. Does anyone have any ideas?

2

Answers


  1. You can solve this issue for permission in decks, like this :

      match /databases/{database}/documents {
        match /decks/{deck} {
          allow update: if request.resource.data.keys().hasOnly(['decks'])  // Only 'decks' field is updated
            && request.resource.data.decks is list  // 'decks' must be a list
            && request.resource.data.decks.size() == resource.data.decks.size() + 1;  // The size must be one more than the current list size
        }
    }
    
    Login or Signup to reply.
  2. I think you may be misunderstanding how request.resource works. The request.resource contains the entire document as it will exist after the write operation (if that operation is allowed).

    So this line in your rules:

    request.resource.data.keys().hasOnly(['decks']) &&
    

    This says that the document after it has been updated may only contain a decks field. If there are any other fields in the document after the update, the update is rejected.

    If you only want the decks field to be updated, you’ll need to use affectedKeys function. There are some good examples of this in the Firebase documentation on restricting what fields can be updated too. For example, here’s how it allows only certain fields to be updated:

    service cloud.firestore {
      match /databases/{database}/documents {
        match /restaurant/{restId} {
        // Allow a client to update only these 6 fields in a document
          allow update: if (request.resource.data.diff(resource.data).affectedKeys()
            .hasOnly(['name', 'location', 'city', 'address', 'hours', 'cuisine']));
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search