By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
rocoderesrocoderes
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Notification Show More
Latest News
How to set the dropdown value by clicking on a table row
Javascript – How to set the dropdown value by clicking on a table row
JavaScript
Attempting to increase the counter, when the object's tag exist
Javascript – Attempting to increase the counter, when the object’s tag exist
JavaScript
Cycle2 JS center active slide
Javascript – Cycle2 JS center active slide
JavaScript
Can import all THREE.js post processing modules as ES6 modules except OutputPass
Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass
JavaScript
How to return closest match for an array in Google Sheets Appscript
Javascript – How to return closest match for an array in Google Sheets Appscript
JavaScript
Aa
Aa
rocoderesrocoderes
Search
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Follow US
High Quality Design Resources for Free.
rocoderes > JavaScript > Javascript – Realtime Database “All or Nothing” transactions
JavaScript

Javascript – Realtime Database “All or Nothing” transactions

Admin
Last updated: 2024/01/12 at 2:27 PM
Admin
Share
5 Min Read
Realtime Database "All or Nothing" transactions

Problem:

I’m trying to figure out if Firebase Realtime databases have an “All or nothing” Transaction similar to the one from Firestore – Transaction.

Contents
Problem:Solution:

I need to perform this sort of transaction on a Cloud function.
To add more context to this, I’m trying to listen to the creation of new children to a node. Whenever a new child node gets added, I want to perform a bunch of actions (reads, writes, updates, and deletes), and I want to ensure that either all of them go through or none of them do. Also, I want to ensure that the data changes to any of the above-mentioned nodes during this time don’t affect this transaction.

Here’s what I’m doing:

export const matchPlayers = functions.database
  .ref(`match_queue/{newEntryId}`)
  .onCreate((createdChild) => {
       const queue = db.ref('match_queue');
       queue.get().then((snapshot) => {
           snapshot.forEach((child) => {
               if (child.key != createdChild.key && !child.val().matched) {
                 matchPlayers(child, createdChild);
                 return;
               }
           });
       });
       return null;
  });

function matchPlayers(
  player1Snapshot: DataSnapshot,
  player2Snapshot: DataSnapshot,
) {
  const player1 = player1Snapshot.val();
  const player2 = player2Snapshot.val();

  const match = {
    player_1_id: player1.id,
    player_2_id: player2.id,
  };

  const matchId = db.ref("matches").push(match).key;
  const promises = [];
  promises.push(db.ref("users")
    .child(player1.id).update({
      current_match_id: matchId,
    }));
  promises.push(db.ref("users")
    .child(player2.id).update({
      current_match_id: matchId,
    }));
  promises.push(db
    .ref(`${MATCH_QUEUE_REF}/` + player1Snapshot.key).remove());
  promises.push(db
    .ref(`${MATCH_QUEUE_REF}/` + player2Snapshot.key).remove());
  return Promise.all(promises);
}

This above function listens for the creation of new children nodes to “match_queue”.
If there is a new child added, I want to perform the following actions:

  1. Read match_queue’s children and perform some logic (basically match the created node with a different child node from “match_queue” – simple matchmaking).
  2. Add a new child node to “matches” (a different parent node).
  3. Update the individual “users” that got matched.
  4. And finally, delete the “createdChild” node from above.

I’m able to perform the DB updates mentioned here, but I’m not able to figure out how to ensure that while this transaction is going on and new data get’s written to the db, these two children that are currently getting matched, don’t get picked up again.

So say the children to match_queue are “abc” and “def”. When “def” gets created, the cloud function runs and tries to match it to “abc”. But during this transaction, another child “ghi” gets created. I want to ensure that “ghi” isn’t getting matched to either “abc” or “def” since they’re in a transaction that’s in progress.

Solution:

Firebase has two mechanisms for performing transactional write operations:

  • Transactions that read from a single path in the database and then write a new value to that path.
  • Multi-path writes that write to multiple paths in the database atomically, but can’t read any data.

From a quick scan it looks like you need to update multiple, disjunct paths in the database, so a multi-path write seems the way to go. Something like:

const matchId = db.ref("matches").push(match).key;
const updates = {};
updates[`users/$player1.id}/current_match_id`] = matchId;
updates[`users/${player2.id}/current_match_id`] = matchId;
updates[`${MATCH_QUEUE_REF}/${player1Snapshot.key}`] = null; // writing null removes the node
updates[`${MATCH_QUEUE_REF}/${player2Snapshot.key}`] = null;
return db.ref().update(updates);

Advanced update

If you want to prevent another user from modifying a value while you perform a multi-path update, you’re essentially looking for a multi-path transaction which Firebase Realtime Database doesn’t natively support. You can roll your own multi-path transaction mechanism, but that’s definitely quite involved.

I typically include some version number in the data I read, that I then write back/increment in the multi-path updates, and check in security rules that the version is what I expect. In the client-codeyouI then catch write rules failure and retry. That’s pretty much what transactions do automatically, just with a lot more work (and knowledge about your use case) on your own part.

Also see:

  • How can I use a transaction while performing a multi-location update in Firebase?
  • Is the way the Firebase database quickstart handles counts secure?
  • Firebase – One transaction for 2 paths in real time database
  • how to write batched transactions for firebase admin realtime db?
  • How can I combine updateChildren and runTransaction?

Related

Subscribe to Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

Share this Article
Facebook Twitter Email Print
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article AlpineJS: @click doesn't work on tag Javascript – AlpineJS: @click doesn’t work on
Next Article JavaScript: Passing no parameter if option doesn't exist? Javascript – JavaScript: Passing no parameter if option doesn’t exist?
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

- Advertisement -

You Might Also Like

How to set the dropdown value by clicking on a table row

Javascript – How to set the dropdown value by clicking on a table row

February 11, 2024
Attempting to increase the counter, when the object's tag exist

Javascript – Attempting to increase the counter, when the object’s tag exist

February 11, 2024
Cycle2 JS center active slide

Javascript – Cycle2 JS center active slide

February 10, 2024
Can import all THREE.js post processing modules as ES6 modules except OutputPass

Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass

February 10, 2024
rocoderesrocoderes
Follow US

Copyright © 2022 All Right Reserved By Rocoderes

  • Home
  • About us
  • Contact us
  • Disclaimer
Join Us!

Subscribe to our newsletter and never miss our latest news, podcasts etc.

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?