如何在Firebase实时数据库中批量获取多文档ID对应的数据?
如何在Firebase Realtime Database中一次请求获取多个指定ID的文档
我需要通过一次请求获取多个指定ID的文档,目前只能逐个调用接口获取,每个请求耗时600ms,这种方式扩展性很差。尝试过使用onValue但不知道如何仅获取指定文档ID的数据。现有单个文档获取函数和串行批量获取函数如下:
async function fetchByDocumentIdHelper( database: Database, documentId: string ): Promise<AgencyRealtimeModel> { const dbRef = ref(database); const query = child(dbRef, `agencies/${documentId}`); const dataSnapshot = await get(query); if (!dataSnapshot.exists()) { return {}; } const id = documentId; const data = dataSnapshot.val(); const model: AgencyRealtimeModel = { id: id, data: data, }; return model; }
async function fetchByDocumentIdsHelper( database: Database, documentIds: string[] ): Promise<AgencyRealtimeModel[]> { const models: AgencyRealtimeModel[] = []; for (let i = 0; i < documentIds.length; i++) { const documentId = documentIds[i]; const model = await fetchByDocumentIdHelper(database, documentId); models.push(model); } return models; }
方案1:单次请求拉取父节点后过滤(最优)
Realtime Database支持直接拉取整个agencies节点的数据,之后在客户端筛选出需要的文档ID,这样只需要一次网络请求,彻底解决多请求的耗时问题。
修改后的批量获取函数:
async function fetchByDocumentIdsHelper( database: Database, documentIds: string[] ): Promise<AgencyRealtimeModel[]> { const dbRef = ref(database); const agenciesRef = child(dbRef, 'agencies'); const dataSnapshot = await get(agenciesRef); if (!dataSnapshot.exists()) { return []; } const allAgencies = dataSnapshot.val() as Record<string, unknown>; // 筛选指定ID的文档并转换为目标模型 return documentIds.map(documentId => ({ id: documentId, data: allAgencies[documentId] || {}, })); }
优势:
- 仅发起一次网络请求,总耗时从
n*600ms骤降到单次请求的耗时 - 逻辑简单,无需处理多请求的并发问题
- 保持和原函数一致的行为:不存在的ID返回
data: {}
方案2:并行请求优化(次优,适合父节点数据量极大的场景)
如果agencies节点数据量非常庞大,一次拉取全量数据会占用过多带宽,可以用Promise.all将多个请求并行发起,总耗时会接近单个请求的耗时(远低于串行循环):
async function fetchByDocumentIdsHelper( database: Database, documentIds: string[] ): Promise<AgencyRealtimeModel[]> { // 同时发起所有请求 const requestPromises = documentIds.map(id => fetchByDocumentIdHelper(database, id)); // 等待所有请求完成后返回结果 return Promise.all(requestPromises); }
优势:
- 并行请求大幅缩短总耗时,比如10个文档的总耗时从6秒降到约600ms
- 无需修改原单个文档获取函数,直接复用现有逻辑
关于onValue的使用方式
onValue用于监听节点的实时数据变化,同样可以通过监听agencies节点,在回调中筛选指定ID的文档,实现实时更新:
// 订阅指定ID的文档实时更新,返回取消订阅的函数 function subscribeToDocumentIds( database: Database, documentIds: string[], onUpdate: (models: AgencyRealtimeModel[]) => void ): () => void { const dbRef = ref(database); const agenciesRef = child(dbRef, 'agencies'); return onValue(agenciesRef, (snapshot) => { if (!snapshot.exists()) { onUpdate([]); return; } const allAgencies = snapshot.val() as Record<string, unknown>; const updatedModels = documentIds.map(id => ({ id, data: allAgencies[id] || {}, })); onUpdate(updatedModels); }); } // 使用示例: // const unsubscribe = subscribeToDocumentIds(db, ['id1', 'id2'], (models) => { // console.log('实时更新的数据:', models); // }); // 取消订阅时调用 unsubscribe();
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

