3
votes

I am trying to create a document reference, set up an onsnapshot listener, save the document and then upload a file which will trigger a cloud function which will make updates to the document i am listening to. But onSnapshot gives a permissions error of 'FirebaseError: Missing or insufficient permissions.' after the snapshot has run once (I guess for the initial state).

I have tried running simulations of accessing and writing the data in the firebase console and it works without any errors

const db = window.firebase.firestore()
const newBaseRef = db.collection('base').doc()

newBaseRef.onSnapshot(doc => {
  console.log('Current data: ', doc.data())
}, function (error) {
  throw error // THIS ALWAYS GETS HIT
})

newBaseRef.set({
  uid: window.firebase.auth().currentUser.uid,
  createdAt: window.firebase.firestore.FieldValue.serverTimestamp()
})

here are my security rules

service cloud.firestore {
  match /databases/{database}/documents {
    match /printset/{document=**} {
      allow read, update, delete: if request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }

    match /file/{document=**} {
      allow read, update, delete: if request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }

    match /base/{document=**} {
      allow read, update, delete: if request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }
  }
}

I dont expect the error callback to run

1
Would help to also post your security rules.Philip
Can you try with match /base/{baseId}/{document=**}. match /base/{document==**} should work. But i wonder. Also .doc() seems to be empty, Is that intentional?Philip
Yes it is intentional as I wanted to set up the listener to receive the changes that the cloud function makes to the document. So i create the reference, set up the listener and then use .set to create the doc on the server. I can try your suggestion now.... update: the change to the security rules made no differenceoliver

1 Answers

2
votes

newBaseRef.set() return Promise.

So when newBaseRef.onSnapshot() is called, newBaseRef.data().uid doesn't set yet.

See:

You should call newBaseRef.onSnapshot() after Promise.resolve().

const db = window.firebase.firestore()
const newBaseRef = db.collection('base').doc()


newBaseRef.set({
  uid: window.firebase.auth().currentUser.uid,
  createdAt: window.firebase.firestore.FieldValue.serverTimestamp()
}).then(() => {
  newBaseRef.onSnapshot(doc => {
    console.log('Current data: ', doc.data())
  }, function (error) {
    throw error // THIS ALWAYS GETS HIT
  })
})

And more.

If you want to only Insert then you should use newBaseRef.add({}).

If you want to Insert or DeleteInsert(Replace All Data) then you should use newBaseRef.set({}).

If you want to InsertUpdate or Update then you should use newBaseRef.set({}, {merge, true}).

If you want to only Update then you should use newBaseRef.update({}).

If you want to InsertUpdate or Update then change your security rules to the following setting.

service cloud.firestore {
  match /databases/{database}/documents {

    match /printset/{document=**} {
      allow read, update, delete: if request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }

    match /file/{document=**} {
      allow read, update, delete: if request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }

    match /base/{document=**} {
      allow read, delete: if request.auth.uid == resource.data.uid
      allow update: if resource == null || request.auth.uid == resource.data.uid
      allow create: if request.auth.uid != null;
    }
  }
}