Cost optimization (read/write reduction) in Firebase - Time & Space Complexity
When using Firebase, each read or write operation costs money and time.
We want to understand how these costs grow as we do more operations.
Analyze the time complexity of the following operation sequence.
const db = firebase.firestore();
async function fetchUsers(userIds) {
const users = [];
for (const id of userIds) {
const doc = await db.collection('users').doc(id).get();
users.push(doc.data());
}
return users;
}
This code fetches user data for each user ID by reading documents one by one.
Identify the API calls, resource provisioning, data transfers that repeat.
- Primary operation: Reading a user document from Firestore.
- How many times: Once for each user ID in the input list.
Each user ID causes one read operation, so the total reads grow directly with the number of users.
| Input Size (n) | Approx. API Calls/Operations |
|---|---|
| 10 | 10 reads |
| 100 | 100 reads |
| 1000 | 1000 reads |
Pattern observation: The number of reads grows linearly as the input size increases.
Time Complexity: O(n)
This means the cost and time increase directly in proportion to how many user IDs we fetch.
[X] Wrong: "Fetching multiple users one by one is just as cheap as fetching them all at once."
[OK] Correct: Each separate read counts as a separate operation and adds cost and time, so doing many single reads is more expensive than batching.
Understanding how costs grow with reads and writes helps you design efficient Firebase apps that save money and run faster.
"What if we changed the code to fetch all user documents in a single batch request? How would the time complexity change?"
Practice
Solution
Step 1: Understand Firebase read costs
Firebase charges for each document read. Continuous listeners keep reading data repeatedly, increasing costs.Step 2: Choose cost-saving read method
Reading data once fetches the document a single time, reducing read operations and costs.Final Answer:
Read data once instead of using continuous listeners -> Option CQuick Check:
Minimize reads = Read once [OK]
- Thinking continuous listeners cost less
- Assuming multiple writes reduce costs
- Overwriting entire documents unnecessarily
Solution
Step 1: Identify update methods in Firebase
Usingset()with{merge: true}updates only specified fields without overwriting the whole document.Step 2: Check options for correctness
db.collection('users').doc('abc').set({age: 30}, {merge: true}) usesset()withmerge: true, which is the correct syntax for partial updates.Final Answer:
db.collection('users').doc('abc').set({age: 30}, {merge: true}) -> Option AQuick Check:
Partial update = set with merge true [OK]
- Using set without merge overwrites entire document
- Using update() with invalid merge option
- Using invalid option {overwrite: false}
const batch = db.batch();
batch.set(db.collection('users').doc('a'), {name: 'Alice'});
batch.set(db.collection('users').doc('b'), {name: 'Bob'});
batch.commit();Solution
Step 1: Understand batch writes in Firebase
Batch writes group multiple writes to execute atomically but each write counts as a separate operation for billing.Step 2: Count write operations in the snippet
Twosetcalls inside the batch mean two write operations charged whencommit()runs.Final Answer:
Two separate write operations are charged -> Option AQuick Check:
Batch writes count each write separately [OK]
- Thinking batch commit charges only once
- Assuming writes are free before commit
- Believing writes charge only if doc exists
db.collection('users').doc('user1').set({email: 'new@example.com'});Solution
Step 1: Identify why entire document is overwritten
Usingset()without{merge: true}replaces the whole document, causing data loss.Step 2: Fix the code to update only one field
Add{merge: true}toset()to update only the email field without overwriting others.Final Answer:
Missing {merge: true} option in set() -> Option DQuick Check:
Partial update needs merge true [OK]
- Using set() without merge option
- Confusing update() and set() usage
- Assuming field names cause overwrite
Solution
Step 1: Understand cost impact of writes
Each write operation costs money. Multiple separate writes increase cost and risk overwriting data.Step 2: Choose efficient update method
Batch writes combine multiple updates into one commit, reducing network overhead. Usingset()with{merge: true}updates only needed fields without overwriting.Final Answer:
Use a batch write with set() and merge: true for all updates -> Option BQuick Check:
Batch + merge = efficient partial updates [OK]
- Overwriting entire documents unnecessarily
- Using many separate update calls
- Ignoring batch writes for multiple updates
Ready to prove it?
Pass the test and this pattern moves unknown
