Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to handle null values on firebase transaction api

I have a function that is decrementing user credits on firebase realtime database values with a transaction. As suggested in Firebase transaction API call current data is null transaction current value occasionally returns as null.

I've made a guard for the null case and returned 0 so the transaction function fires again until it gets the actual credit value.

function charge(cost, description) {
  return new Promise((resolve, reject) => {
    const creditRef = db.ref(`credits/${userid}`)
    ref.transaction(function(current) {
      console.log(`${description} current value: ${current}`)
      if (current === null) {
        console.log(`${description} returns 0 `)
        return 0
      }
      if (cost > current || current === 0) {
        //not enough credits return without committing
        console.log(`${description} aborts `)
        return
      }
      //commit the new credit value
      console.log(`${description} returns ${current} - ${cost}`)
      return current - cost
    },
    (error, commited, snapshot) => {
      if (error) {
        reject(error)
      }
      else {
        if (commited) {
            //user has enough credits
            resolve()
        }
        else {
            //not enough credits
            reject('no commit')
        }
    }
  })
}

However, in a case where 2 charge functions are fired back to back, the second call will get a current value of 0 (which is probably the returned 0 on the first charge call). So it will prematurely exit assuming that the user doesn't have enough credits. When both functions resolve the final credit value will be 3 and the second charge call will be ignored.

// User has 5 credits 
charge(3, 'first call').then(() => console.log('first call success')
// transaction function returns 0 since current value is null
charge(2, 'second call').then(() => console.log('second call success')

Console log output:

first call current value: null

first call returns 0

second call current value: 0

second call aborts

first call current value: 5

first call returns 5 - 3

first call success

second call no commit

So the second charge call ends up not going through when user had enough credits. What is the proper way to handle firebase transaction null value cases?

like image 486
Saccarab Avatar asked Nov 22 '25 02:11

Saccarab


1 Answers

In the case you get null from the database, you should make no change. Since you get null, also return null.

So:

const ref = firebase.database().ref(`59571450`)
function charge(cost, description) {
  return new Promise((resolve, reject) => {
    ref.transaction(function(current) {
      console.log(`${description} current value: ${current}`);
      if (current === null) {
        console.log(`${description} returns null`)
        return null;
      }
      if (cost > current) {
        //not enough credits return without committing
        console.log(`${description} aborts `)
        return
      }
      //commit the new credit value
      console.log(`${description} returns ${current} - ${cost}`)
      return current - cost
    },
    (error, commited, snapshot) => {
      if (error) {
        reject(error)
      }
      else {
        if (commited) {
            //user has enough credits
            resolve()
        }
        else {
            //not enough credits
            reject('no commit')
        }
      }
    });
  });
}
                     

ref.set(5).then(() => {
  charge(3, 'first call').then(() => console.log('first call success'))
  charge(2, 'second call').then(() => console.log('second call success'))
})

When run this gives this output:

first call current value: null

first call returns null

second call current value: null

second call returns null

first call current value: 5

first call returns 5 - 3

second call current value: 2

second call returns 2 - 2

first call success

second call success

For a working version of this code, see: https://jsbin.com/xefebul/1/edit?js,console

like image 89
Frank van Puffelen Avatar answered Nov 24 '25 19:11

Frank van Puffelen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!