Bird
Raised Fist0
Firebasecloud~10 mins

Transaction basics in Firebase - Step-by-Step Execution

Choose your learning style10 modes available
Process Flow - Transaction basics
Start Transaction
↓
Read Data Snapshot
↓
Apply Update Logic
↓
Attempt Commit
↓
Commit
A transaction reads data, applies changes, tries to commit, and retries if conflicts occur.
Execution Sample
Firebase
db.runTransaction(transaction => {
  return transaction.get(docRef).then(doc => {
    const newCount = doc.data().count + 1;
    transaction.update(docRef, { count: newCount });
  });
});
This code reads a document's count, increments it by one, and updates it atomically.
Process Table
StepActionData ReadUpdate AppliedCommit AttemptResult
1Start transactionN/AN/ANoTransaction started
2Read document snapshot{"count": 5}N/ANoData read successfully
3Calculate new count5count = 6NoUpdate prepared
4Apply update5count = 6NoUpdate staged
5Attempt commit5count = 6YesCommit successful
6Transaction endsN/AN/ANoTransaction complete
💡 Commit successful, transaction ends without retry
Status Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
countundefined5666
transactionStatenot startedstartedupdate preparedupdate stagedcommitted
Key Moments - 3 Insights
Why does the transaction retry sometimes?
If the commit fails due to data changes by others, the transaction retries from reading data again (see concept_flow and step 5 in execution_table).
Is the data read inside the transaction always the latest?
Yes, the transaction reads the latest data snapshot at step 2 before applying updates, ensuring consistency.
What happens if the update logic depends on stale data?
The transaction will detect conflicts at commit and retry, so the update logic always runs on fresh data (see retry path in concept_flow).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of 'count' after step 3?
A5
B6
Cundefined
D7
💡 Hint
Check the 'Data Read' and 'Update Applied' columns at step 3 in execution_table.
At which step does the transaction try to save changes to the database?
AStep 5
BStep 4
CStep 2
DStep 6
💡 Hint
Look for 'Attempt commit' column in execution_table.
If the commit fails, what happens next according to the concept_flow?
ATransaction ends immediately
BUpdate is discarded without retry
CTransaction retries from reading data again
DTransaction commits anyway
💡 Hint
See the retry loop in the concept_flow ASCII diagram.
Concept Snapshot
Transaction basics in Firebase:
- Start transaction
- Read latest data snapshot
- Apply update logic
- Attempt commit
- If commit fails, retry transaction
- Ensures atomic, consistent updates
Full Transcript
A Firebase transaction starts by reading the latest data snapshot. Then it applies update logic based on that data. Next, it attempts to commit the changes. If the commit succeeds, the transaction ends. If the commit fails due to concurrent changes, the transaction retries from reading data again. This process ensures atomic and consistent updates to the database.

Practice

(1/5)
1. What is the main purpose of using a transaction in Firebase?
easy
A. To speed up data retrieval
B. To ensure data changes are safe and consistent
C. To store large files
D. To send notifications to users

Solution

  1. Step 1: Understand transaction purpose

    Transactions are designed to keep data changes safe and consistent when multiple users might update the same data.
  2. Step 2: Eliminate unrelated options

    Speeding up retrieval, storing files, or sending notifications are not the main goals of transactions.
  3. Final Answer:

    To ensure data changes are safe and consistent -> Option B
  4. Quick Check:

    Transaction purpose = safe and consistent data [OK]
Hint: Transactions protect data integrity during concurrent updates [OK]
Common Mistakes:
  • Thinking transactions speed up data retrieval
  • Confusing transactions with file storage
  • Assuming transactions send notifications
2. Which of the following is the correct way to start a transaction in Firebase Realtime Database?
easy
A. database.ref('path').transaction(updateFunction)
B. database.ref('path').setTransaction(updateFunction)
C. database.transaction('path', updateFunction)
D. database.ref('path').runTransaction(updateFunction)

Solution

  1. Step 1: Recall Firebase transaction syntax

    The correct method to start a transaction is calling transaction() on a database reference.
  2. Step 2: Check each option

    database.ref('path').transaction(updateFunction) uses ref('path').transaction(updateFunction), which is correct. Options A, B, and D use incorrect method names or call patterns.
  3. Final Answer:

    database.ref('path').transaction(updateFunction) -> Option A
  4. Quick Check:

    Correct method is .transaction() on ref [OK]
Hint: Use .transaction() on a database reference to start [OK]
Common Mistakes:
  • Using .setTransaction() which does not exist
  • Calling transaction directly on database object
  • Using .runTransaction() which is invalid
3. Consider this transaction code snippet:
database.ref('counter').transaction(currentValue => {
  if (currentValue === null) {
    return 1;
  } else {
    return currentValue + 1;
  }
});
What will be the value of 'counter' after this transaction if it was initially 5?
medium
A. 6
B. 1
C. null
D. 5

Solution

  1. Step 1: Analyze the transaction function logic

    The function checks if the current value is null; if so, it returns 1. Otherwise, it returns currentValue + 1.
  2. Step 2: Apply initial value 5

    Since currentValue is 5 (not null), the function returns 5 + 1 = 6.
  3. Final Answer:

    6 -> Option A
  4. Quick Check:

    5 + 1 = 6 [OK]
Hint: If value exists, transaction adds 1; else sets to 1 [OK]
Common Mistakes:
  • Assuming value stays the same
  • Confusing null check logic
  • Returning 1 regardless of current value
4. What is wrong with this Firebase transaction code?
database.ref('score').transaction(() => {
  database.ref('score').set(10);
  return 20;
});
medium
A. You cannot return a value in a transaction function
B. Calling set() inside transaction causes an error
C. Reads must happen before writes inside the transaction function
D. Transaction function must be async

Solution

  1. Step 1: Understand transaction function rules

    All reads must happen before any writes inside the transaction function to ensure consistency.
  2. Step 2: Identify the problem in code

    The code calls set(10) inside the transaction function before returning a new value, which violates the rule.
  3. Final Answer:

    Reads must happen before writes inside the transaction function -> Option C
  4. Quick Check:

    Transaction rule: read before write [OK]
Hint: Do all reads before any writes inside transaction function [OK]
Common Mistakes:
  • Calling set() inside transaction function
  • Returning a value is allowed and required
  • Thinking transaction function must be async
5. You want to increment a user's points only if their current points are less than 100. Which transaction function correctly implements this logic?
database.ref('users/user1/points').transaction(currentPoints => {
  // Your code here
});
hard
A. if (currentPoints === null) { return 0; } else { return 100; }
B. if (currentPoints >= 100) { return currentPoints + 1; } else { return currentPoints; }
C. return currentPoints + 1;
D. if (currentPoints === null || currentPoints < 100) { return (currentPoints || 0) + 1; } else { return currentPoints; }

Solution

  1. Step 1: Understand the condition to increment points

    Points should increment only if currentPoints is less than 100 or if it is null (no points yet).
  2. Step 2: Check each option logic

    if (currentPoints === null || currentPoints < 100) { return (currentPoints || 0) + 1; } else { return currentPoints; } increments points by 1 if currentPoints is null or less than 100, else returns currentPoints unchanged. This matches the requirement. if (currentPoints >= 100) { return currentPoints + 1; } else { return currentPoints; } increments when points are 100 or more, which is wrong. return currentPoints + 1; always increments ignoring the limit. if (currentPoints === null) { return 0; } else { return 100; } resets points incorrectly.
  3. Final Answer:

    if (currentPoints === null || currentPoints < 100) { return (currentPoints || 0) + 1; } else { return currentPoints; } -> Option D
  4. Quick Check:

    Increment only if points < 100 or null [OK]
Hint: Check null or less than 100 before incrementing [OK]
Common Mistakes:
  • Incrementing points when already 100 or more
  • Ignoring null initial value
  • Resetting points instead of incrementing
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard