javascript - Firebase Web SDK - Transaction causing on('child_added', func.. to be called -
see jsbin.com/ceyiqi/edit?html,console,output verifiable example.
i have reference listening database point
jobs/<key>/list
where <key> teams unique number
under entry point list of jobs
i have listener on point with
this.jobsref.orderbychild('archived') .equalto(false) .on('child_added', function(data) { i have method following transaction:
ref.transaction(function(post) { // correct counter if(post) { // console.log(post); if(active) { // if toggeling on } else { // if toggeling off } } return post; }) when invoking transaction child_added invoked again, giving me duplicate jobs.
is expected behavior? should check see if item has been got before , add array accordingly? or doing wrong?
thanks in advance time
you're hitting interesting edge case in how firebase client handles transactions. transaction function running twice, first on null , on actual data. it's apparent see if listen value events on /jobs, since you'll see:
- initial value
- null (when transaction starts , runs on
null) - initial value again (when transaction runs again on real data)
the null value in step 2 client's initial guess current value. since client doesn't have cached data /jobs (it ignores cached data /jobs/list), guesses null. wrong. unfortunately has been long time, it's unlikely change in current major version of sdk.
and because of null in step 2, you'll child_removed events (which you're not handling right now) , in step 3 you'll child_added events re-add them.
if handled child_removed events, you're items wouldn't end duplicated, still disappear / reappear, isn't desirable. workaround in current setup explicitly tell transaction not run local estimate, can passing in false third parameter:
function transact() { var path = 'jobs/'; var ref = firebase.database().ref(path); ref.transaction(function(post) { return post; }, function(error, committed, snapshot) { if (error) { console.log('transaction failed abnormally!', error); } else if (!committed) { console.log('transaction aborted.'); } else { console.log('transaction completed.'); } }, false); } i'm sorry don't have better solution. said: it's unlikely we'll able change behavior in current generation of sdks.
Comments
Post a Comment