Bird
Raised Fist0
Firebasecloud~10 mins

Optimistic concurrency in Firebase - Step-by-Step Execution

Choose your learning style10 modes available
Process Flow - Optimistic concurrency
Read document snapshot
↓
Make local changes
↓
Attempt to write with version check
↓
Version matches?
No→Conflict detected
↓
Write succeeds
Read data, change locally, then write back only if data version is unchanged to avoid conflicts.
Execution Sample
Firebase
const docRef = firestore.doc('items/item1');
const snapshot = await docRef.get();
const data = snapshot.data();
const version = data.version;
await firestore.runTransaction(async (transaction) => {
  const freshSnapshot = await transaction.get(docRef);
  if (freshSnapshot.data().version !== version) {
    throw new Error('Conflict detected');
  }
  transaction.update(docRef, { count: data.count + 1, version: version + 1 });
});
Reads a document, increments a count and version, then writes back only if version matches.
Process Table
StepActionData Version ReadLocal ChangeVersion CheckWrite Result
1Read document snapshot3N/AN/AN/A
2Increment count locally3count + 1N/AN/A
3Attempt write with version=33count + 1, version=4Check if current version == 3Success
4Write completes4N/AN/ADocument updated with version=4
5Another client tries write with version=33count + 1, version=4Check if current version == 3Fail - Conflict detected
💡 Write fails if document version changed since read, ensuring no overwrite of concurrent updates.
Status Tracker
VariableStartAfter Step 1After Step 2After Step 3After Step 4After Step 5
versionN/A33443 (stale)
countN/Acurrentcurrent + 1current + 1updatedcurrent + 1 (stale)
writeResultN/AN/AN/ASuccessCompletedFail
Key Moments - 2 Insights
Why does the write fail at step 5 even though the client read version 3?
Because between reading and writing, another client updated the document to version 4 (see step 4), so the version check at step 5 fails to prevent overwriting newer data.
What happens if we don't check the version before writing?
Without version check, writes could overwrite concurrent changes, causing data loss or inconsistency (not shown in execution_table but implied by failure at step 5).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the document version after step 4?
A4
B3
C5
D2
💡 Hint
Check the 'Data Version Read' and 'Write Result' columns at step 4.
At which step does the write fail due to a version conflict?
AStep 3
BStep 5
CStep 4
DStep 2
💡 Hint
Look for 'Fail - Conflict detected' in the 'Write Result' column.
If the version check was removed, how would the write result at step 5 change?
AIt would still fail
BIt would cause an error before writing
CIt would succeed and overwrite data
DIt would retry automatically
💡 Hint
Refer to the 'key_moments' explanation about version checks preventing overwrites.
Concept Snapshot
Optimistic concurrency means:
- Read data with a version number
- Make local changes
- Write back only if version unchanged
- Prevents overwriting others' updates
- Common in Firebase to avoid conflicts
Full Transcript
Optimistic concurrency in Firebase means you first read a document including its version number. Then you make changes locally. When you write back, you check if the version is still the same. If yes, the write succeeds and increments the version. If no, the write fails because someone else updated the document meanwhile. This prevents data conflicts and lost updates. The execution table shows reading version 3, updating to 4, and a later write failing because the version changed. This method helps keep data consistent when many clients update the same document.

Practice

(1/5)
1. What is the main purpose of optimistic concurrency in Firebase?
easy
A. To automatically backup data every hour
B. To speed up data retrieval by caching results
C. To encrypt data during transmission
D. To prevent overwriting data by checking for changes before updating

Solution

  1. Step 1: Understand optimistic concurrency concept

    Optimistic concurrency means checking if data changed before saving updates to avoid overwriting others' changes.
  2. Step 2: Match concept to Firebase usage

    Firebase uses transactions to check and update data atomically, which is an example of optimistic concurrency.
  3. Final Answer:

    To prevent overwriting data by checking for changes before updating -> Option D
  4. Quick Check:

    Optimistic concurrency = prevent overwrites [OK]
Hint: Optimistic concurrency checks data before saving updates [OK]
Common Mistakes:
  • Confusing optimistic concurrency with caching
  • Thinking it encrypts data
  • Assuming it backs up data automatically
2. Which Firebase method is used to safely update data with optimistic concurrency?
easy
A. firebase.database().set()
B. firebase.database().transaction()
C. firebase.database().push()
D. firebase.database().once()

Solution

  1. Step 1: Identify methods for data update in Firebase

    Methods like set() overwrite data directly, push() adds new data, once() reads data once.
  2. Step 2: Find method supporting atomic update with retry

    transaction() reads current data, applies update, retries if data changed during update, ensuring safe concurrency.
  3. Final Answer:

    firebase.database().transaction() -> Option B
  4. Quick Check:

    Safe update method = transaction() [OK]
Hint: Use transaction() for atomic updates with concurrency control [OK]
Common Mistakes:
  • Using set() which overwrites without concurrency check
  • Confusing push() with update methods
  • Using once() which only reads data
3. Consider this Firebase transaction code snippet:
const ref = firebase.database().ref('counter');
ref.transaction(current => {
  return (current || 0) + 1;
});

What happens if two users run this code at the same time?
medium
A. The counter increments by 1 only once
B. The counter resets to 0
C. The counter increments by 2 safely without overwriting
D. The transaction fails and throws an error

Solution

  1. Step 1: Understand transaction behavior with concurrent updates

    Firebase transactions read current value, apply update, and retry if data changed during update.
  2. Step 2: Analyze two concurrent increments

    Both users read current value, increment by 1, but Firebase retries one transaction to avoid overwrite, resulting in counter increasing by 2.
  3. Final Answer:

    The counter increments by 2 safely without overwriting -> Option C
  4. Quick Check:

    Concurrent transactions = safe increments [OK]
Hint: Transactions retry to avoid overwriting, so increments add up [OK]
Common Mistakes:
  • Thinking only one increment happens
  • Assuming counter resets
  • Believing transaction throws error on conflict
4. You wrote this Firebase transaction:
ref.transaction(current => {
  current = current + 1;
  return current;
});

But sometimes it throws an error. What is the likely problem?
medium
A. current might be null, causing addition to fail
B. transaction() cannot update numbers
C. You must use set() inside transaction
D. Firebase transactions do not support arrow functions

Solution

  1. Step 1: Check how current value is used

    If current is null (no data yet), adding 1 to null causes an error.
  2. Step 2: Identify fix for null current

    Use (current || 0) + 1 to handle null safely inside transaction.
  3. Final Answer:

    current might be null, causing addition to fail -> Option A
  4. Quick Check:

    Null current causes error in addition [OK]
Hint: Check for null before arithmetic in transactions [OK]
Common Mistakes:
  • Thinking transaction can't update numbers
  • Trying to use set() inside transaction callback
  • Believing arrow functions are unsupported
5. You want to implement a like counter for a post in Firebase using optimistic concurrency. Which approach ensures the counter updates correctly even if many users like simultaneously?
hard
A. Use ref.transaction(currentLikes => (currentLikes || 0) + 1) to increment safely
B. Use ref.set(currentLikes + 1) without checking current value
C. Read currentLikes once, then call ref.set(currentLikes + 1)
D. Use ref.push() to add a new like entry instead of counting

Solution

  1. Step 1: Understand concurrency risks with simple set()

    Using set() without checking current value risks overwriting likes if multiple users update simultaneously.
  2. Step 2: Use transaction for atomic increments

    transaction() reads current value, increments safely, and retries if data changed, ensuring correct count.
  3. Step 3: Evaluate other options

    Reading once then setting risks race conditions; push() adds entries but does not increment counter directly.
  4. Final Answer:

    Use ref.transaction(currentLikes => (currentLikes || 0) + 1) to increment safely -> Option A
  5. Quick Check:

    Safe counter update = transaction() increment [OK]
Hint: Use transaction() with (current || 0) + 1 for safe counters [OK]
Common Mistakes:
  • Using set() without concurrency control
  • Reading once then setting causing race conditions
  • Confusing push() with incrementing counters
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