firebase / firebase/firebase-js-sdk
`snapshot.forEach()` fails on snapshots from `child_added` events when using `orderByChild()` queries
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 37
Description
### Operating System
macOS Ventura 13.4, Darwin 24.4.0
### Environment (if applicable)
Node.js v20.18.0
### Firebase SDK Version
12.0.0
### Firebase SDK Product(s)
Database
### Project Tooling
TypeScript, Jest testing framework
### Detailed Problem Description
When using Firebase Realtime Database with `orderByChild()` queries, calling `snapshot.forEach()` on snapshots received from `child_added` events throws an error: `"No index defined for "`. This occurs even when the database is offline or when proper indexes are defined in security rules.
**What I was trying to achieve:**
- Listen for `child_added` events on a query ordered by a child field
- Iterate through the snapshot's children using `snapshot.forEach()`
**What actually happened:**
- The `child_added` event fires correctly and the snapshot contains the expected data
- Calling `snapshot.forEach()` throws: `Error: No index defined for createdAt`
- The same `forEach()` call works perfectly when called on a fresh snapshot obtained via `get(snapshot.ref)`
**Error message:**
```
BUG: No index defined for createdAt
```
### Steps and code to reproduce issue
```javascript
import { initializeApp } from "firebase/app";
import {
getDatabase,
ref,
set,
get,
query,
orderByChild,
onChildAdded,
goOffline,
} from "firebase/database";
const app = initializeApp({
databaseURL: "https://test-bug-repro.firebaseio.com",
}, "bug-repro-modern");
const db = getDatabase(app);
goOffline(db);
const testData = {
items: {
item1: {
createdAt: 1741445778252,
},
},
};
async function reproduceOrderByChildForEachBug() {
set(ref(db), testData);
const itemsRef = ref(db, "items");
const q = query(itemsRef, orderByChild("createdAt"));
onChildAdded(q, async (snapshot) => {
console.log(`Received onChildAdded for: ${snapshot.key}`);
// This forEach call fails
try {
snapshot.forEach((child) => {
console.log(`Child: ${child.key}`);
return undefined;
});
} catch (error) {
console.error(`BUG: ${error.message}`); // "No index defined for createdAt"
}
// This workaround works
const freshSnapshot = await get(snapshot.ref);
freshSnapshot.forEach((child) => {
console.log(`Child (fresh): ${child.key}`);
return undefined;
});
});
}
reproduceOrderByChildForEachBug();
```
## Expected vs Actual Behavior
**Expected behavior:** `snapshot.forEach()` should work on snapshots from `child_added` events just as it works on fresh snapshots.
**Actual behavior:** `snapshot.forEach()` throws an index error on snapshots from `child_added` events, requiring a workaround of fetching a fresh snapshot first.
## Workaround
The current workaround is to fetch a fresh snapshot before calling `forEach()`:
```javascript
// Instead of calling forEach directly on the child_added snapshot:
// snapshot.forEach(callback); // ❌ Fails
// Use this workaround:
const freshSnapshot = await get(snapshot.ref);
freshSnapshot.forEach(callback); // ✅ Works
```
Contributor guide
Assessment
This issue has not been assessed yet.