Mr Jax
Mr Jax

Reputation: 1017

Cloud Functions: Transaction with FieldValue.increment() not running atomically

I have a Cloud Functions transaction that uses FieldValue.increment() to update a nested map, but it isn't running atomically, thus the value updates aren't accurate (running the transaction in quick succession results in an incorrect count).

The function is fired via:

export const updateCategoryAndSendMessage= functions.firestore.document('events/{any}').onUpdate((event, context) => {

which include the following transaction:

db.runTransaction(tx => {
    const categoryCounterRef = db.collection("data").doc("categoryCount")
    const intToIncrement = event.after.data().published == true ? 1 : -1;
    const location = event.after.data().location;

    await tx.get(categoryCounterRef).then(doc => {

        for (const key in event.after.data().category) {
            event.after.data().category[key].forEach(async (subCategory) => {
                const map = { [key]: { [subCategory]: FieldValue.increment(intToIncrement) } };
               await tx.set(categoryCounterRef, { [location]: map }, { merge: true })
            })
        }
    },
    ).then(result => {
        console.info('Transaction success!')
    })
        .catch(err => {
            console.error('Transaction failure:', err)
        })
}).catch((error) => console.log(error));

Example:

Value of field to increment: 0

Tap on button that performs the function multiple times in quick succession (to switch between true and false for "Published")

Expected value: 0 or 1 (depending on whether reference document value is true or false)

Actual value: -3, 5, -2 etc.

As far as I'm aware, transactions should be performed "first come, first served" to avoid inaccurate data. It seems like the function isn't "queuing up" correctly - for lack of a better word.

I'm a bit stumped, would greatly appreciate any guidance with this.

Upvotes: 4

Views: 162

Answers (1)

Mr Jax
Mr Jax

Reputation: 1017

Oh goodness, I was missing return...

return db.runTransaction(tx => {

Upvotes: 2

Related Questions