Firebase - 按孙节点键查询问题求助
Hey there! Let's work through this Firebase database structure and query issue. First, I can guess that your current setup probably nests user IDs inside each list, which makes it hard to reverse-engineer "all lists that include id1"—since Firebase Realtime Database (and Firestore, for that matter) doesn't support deep cross-queries efficiently.
Let's start with a common problematic structure (what I suspect you might have):
{ "lists": { "idList1": { "name": "Weekly Groceries", "users": { "id1": "Alice", "id3": "Charlie" } }, "idList2": { "name": "Project Milestones", "users": { "id1": "Alice" } }, "idList3": { "name": "Fitness Goals", "users": { "id2": "Bob" } } } }
The problem here is that to find all lists with id1, you'd have to load every single list and check if users/id1 exists—super inefficient, especially as your dataset grows.
The Fix: Denormalize with a Reverse Index
Firebase thrives when you structure data for the queries you actually need. For your use case, add a reverse index that maps user IDs directly to the lists they're part of. Here's the optimized structure:
{ "lists": { "idList1": { "name": "Weekly Groceries", "users": { "id1": true, "id3": true } }, "idList2": { "name": "Project Milestones", "users": { "id1": true } }, "idList3": { "name": "Fitness Goals", "users": { "id2": true } } }, "userToLists": { "id1": { "idList1": true, "idList2": true }, "id2": { "idList3": true }, "id3": { "idList1": true } } }
This way, you get two key benefits:
- You can instantly fetch all list IDs for
id1fromuserToLists/id1 - You can still verify which users are in a list by checking the
usersnode of each list
How to Query for id1's Lists (Realtime Database)
Here's a JavaScript example to get exactly what you need (idList1 and idList2):
// Step 1: Get all list IDs associated with id1 firebase.database().ref('userToLists/id1').once('value') .then(snapshot => { const listIds = Object.keys(snapshot.val()); // Step 2: Fetch details for each list ID const fetchListPromises = listIds.map(listId => firebase.database().ref(`lists/${listId}`).once('value') ); return Promise.all(fetchListPromises); }) .then(listSnapshots => { const userLists = listSnapshots.map(snap => ({ id: snap.key, ...snap.val() })); console.log('Lists for id1:', userLists); // Output will include idList1 and idList2 with their full details }) .catch(err => console.error('Error fetching lists:', err));
If You're Using Firestore (Alternative)
If you're on Firestore instead of Realtime Database, the approach is similar but uses collections and documents. Here's a recommended structure:
- A
listscollection where each document has auserIdsfield (a map of{ [userId]: true }) - (Optional) A
userListscollection where each document (keyed by user ID) has an array or map of list IDs
To query lists containing id1 in Firestore:
firebase.firestore().collection('lists') .where('userIds.id1', '==', true) .get() .then(querySnapshot => { const userLists = []; querySnapshot.forEach(doc => { userLists.push({ id: doc.id, ...doc.data() }); }); console.log('Lists for id1:', userLists); }) .catch(err => console.error('Error fetching lists:', err));
Key Takeaway
Firebase NoSQL databases aren't designed like traditional SQL databases—you need to model your data around the queries you want to run. Adding a reverse index eliminates the need for inefficient full-dataset scans and makes your query fast and scalable.
内容的提问来源于stack exchange,提问作者ozzem

