Search code examples
firebasegoogle-cloud-firestorefirebase-security

how to write Firestore security rules to also allow null value and undefined value in a single field?


I have a field in my Firestore document called lastApproval that should be a timestamp if it has a value.

this is my simplified rules

match /users/{userID} {

  allow create: if isValidUserStructure(incomingData())
  allow update: if isValidUserStructure(incomingData())

}

function incomingData() {
  return request.resource.data;
}


function isValidUserStructure(user) {
    return  user.email is string
         && user.fullname is string
         && user.lastApproval is timestamp  // error in here

}

as you can see, isValidUserStructure function will be used to check when creating and updating user document.

when creating user document, that lastApproval field will be null like this

const data = {
  fullname: 'John Doe',
  email: 'my@email.com',
  lastApproval: null
};

await db.collection('users').doc('userIDHere').set(data);

but when updating document, I only want timestamp.

const data = {
  lastApproval: new Date()
};

await db.collection('users').doc('userIDHere').update(data);

and also, I want to pass the security rules if lastApproval is not available, for example, if the user only want to update the fullname like this

const data = {
  fullname: "My New Name"
};

await db.collection('users').doc('userIDHere').update(data);

so I want my security rules to accept timestamp, null and undefined value for lastApproval field

I have tried but error

enter image description here

please help :)


Solution

  • There isn't any type null as far as I know. You can find all available types in the documentation.

    If you want to check if the value is null then try user.lastApproval == null instead. To check if the lastApproval property exists at first place, try this:

    match /collection/{doc} {
      allow write: if 'lastApproval' in request.resource.data && (..otherLogic)
    }
    

    So you can write your function as:

    function isValidUserStructure(user) {
        return  user.email is string
             && user.fullname is string
             && (('lastApproval' in user && user.lastApproval is timestamp) || !('lastApproval' in user)) 
    }