Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloud Functions for Firebase: how to use a Transaction promise?

I am trying to write a function in Cloud Functions that triggers every time a user gets created and which then saves that user into a list of users and finally increments a user counter. However I am not sure if I am using promises correctly.

exports.saveUser = functions.auth.user().onCreate(event => {
    
   const userId = event.data.uid
  
   const saveUserToListPromise = db.collection("users").doc(userId).set({
      "userId" : userId
   })
   
   var userCounterRef = db.collection("users").doc("userCounter");
   
   const transactionPromise = db.runTransaction(t => {
      return t.get(userCounterRef)
          .then(doc => {
              // Add one user to the userCounter
              var newUserCounter = doc.data().userCounter + 1;
              t.update(userCounterRef, { userCounter: newUserCounter });
          });
  })
  .then(result => {
      console.log('Transaction success!');
  })
  .catch(err => {
      console.log('Transaction failure:', err);
  });
  
  return Promise.all([saveUserToListPromise, transactionPromise])

})

I want to make sure that even if many users register at once that my userCounter is still correct and that the saveUser function won't be terminated before the transaction and the save to the list has happened.

So I tried this out and it works just fine however I don't know if this is the correct way of achieving the functionality that I want and I also don't know if this still works when there are actually many users triggering that function at once.

Hope you can help me. Thanks in advance.

like image 511
Max Avatar asked Dec 11 '17 09:12

Max


People also ask

How do I trigger a Firebase cloud function?

Cloud Firestore function triggersTriggered when a document is written to for the first time. Triggered when a document already exists and has any value changed. Triggered when a document with data is deleted. Triggered when onCreate , onUpdate or onDelete is triggered.

What is a promise in Firebase?

Promises are a modern alternative to callbacks for asynchronous code. A promise represents an operation and the future value it may return. It also lets you propagate errors similar to try/catch in synchronous code. You can read about promises in the Firebase SDK on The Firebase Blog, and promises in general on MDN.

When should I use Firebase transaction?

Transactions are useful when you want to update a field's value based on its current value, or the value of some other field. A transaction consists of any number of get() operations followed by any number of write operations such as set() , update() , or delete() .

Do firestore rules apply to cloud functions?

Since Cloud Firestore backend SDKs running in Cloud Functions have privileged access to Cloud Firestore, they will bypass all security rules.


1 Answers

The correct way to perform multiple writes atomically in a transaction is to perform all the writes with the Transaction object (t here) inside the transaction block. This ensures at all of the writes succeed, or none.

exports.saveUser = functions.auth.user().onCreate(event => {
    const userId = event.data.uid
    return db.runTransaction(t => {
        const userCounterRef = db.collection("users").doc("userCounter")
        return t.get(userCounterRef).then(doc => {
            // Add one user to the userCounter
            t.update(userCounterRef, { userCounter: FirebaseFirestore.FieldValue.increment(1) })
            // And update the user's own doc
            const userDoc = db.collection("users").doc(userId)
            t.set(userDoc, { "userId" : userId })
        })
    })
    .then(result => {
        console.info('Transaction success!')
    })
    .catch(err => {
        console.error('Transaction failure:', err)
    })
})
like image 58
Doug Stevenson Avatar answered Sep 21 '22 01:09

Doug Stevenson