Firebase Firestore多in查询如何合并后通过collectionData返回
Firestore
in查询超10个条件的结果合并方案 问题说明
Firestore的in操作符仅支持等值匹配条件数量不超过10的查询,当待匹配值数量大于10时,需要将目标数组拆分为多个长度为10的子数组,分别初始化多个查询请求。
当数组长度小于等于10时,可直接构造查询对象q,通过return collectionData(q, { idField: 'id' });返回结果;但拆分得到q0、q1等多个查询对象时,无法像返回单个查询q那样统一返回所有查询的实时合并结果。
原问题示例代码如下:
constructor(private firestore: Firestore) { } getUserChats() { const userId = '12345678910'; const userRef = doc(this.firestore, `users/${userId}`); return docData(userRef).pipe( switchMap((data) => { let userChats = data.chats; let chatsRef = collection(this.firestore, 'chats'); if (userChats.length <= 10) { //in操作符最多支持10个匹配值,长度符合要求时直接查询 let q = query(chatsRef, where(documentId(), 'in', userChats)); return collectionData(q, { idField: 'id' }); } else { //将userChats拆分为长度10的子数组,以下为硬编码的示例 let q0 = query(chatsRef, where(documentId(), 'in', userChats.slice(0, 10))); let q1 = query(chatsRef, where(documentId(), 'in', userChats.slice(10, 20))); //... //如何合并q0、q1等多个查询的结果,保持和单个查询一致的返回格式? return collectionData(????????????????, { idField: 'id' }); } }) ); }
实现方案
利用RxJS的组合操作符处理多个Observable的合并即可,不需要修改原有返回格式,实时更新的行为和单个查询完全一致:
- 通用分片逻辑:不需要单独判断数组长度是否小于10,统一按每10个值为一组切分待匹配数组,为每个分片生成对应的
collectionDataObservable - 用
combineLatest组合所有分片查询的Observable,每次任意分片有数据更新时,自动将所有分片的结果合并为单个数组返回,保持和单个查询完全一致的响应式行为
完整实现代码:
// 按需引入RxJS操作符 import { combineLatest, map } from 'rxjs'; constructor(private firestore: Firestore) { } getUserChats() { const userId = '12345678910'; const userRef = doc(this.firestore, `users/${userId}`); return docData(userRef).pipe( switchMap((data) => { const userChats = data.chats; const chatsRef = collection(this.firestore, 'chats'); const chunkSize = 10; const queryObservables = []; // 自动按10个一组切分,生成分片查询 for (let i = 0; i < userChats.length; i += chunkSize) { const idChunk = userChats.slice(i, i + chunkSize); const chunkQuery = query(chatsRef, where(documentId(), 'in', idChunk)); queryObservables.push(collectionData(chunkQuery, { idField: 'id' })); } // 合并所有分片结果,返回格式和单个collectionData完全一致 return combineLatest(queryObservables).pipe( map(results => results.flat()) ); }) ); }
补充说明
- 当待匹配数组长度≤10时,上述逻辑只会生成1个查询Observable,
combineLatest的返回行为和直接返回单个collectionData完全一致,不需要单独写分支判断 - 所有分片查询为并行发起,不会产生额外的串行等待开销
- 该实现完整保留Firestore的实时更新能力:任意分片下的文档发生变更时,都会自动推送最新的合并后结果,和单查询的响应逻辑无差异
- 如果存在数据重复的极端场景,可以在
map操作符中增加按文档ID去重的逻辑:map(results => { const allChats = results.flat(); // 按文档id去重 return Array.from(new Map(allChats.map(chat => [chat.id, chat])).values()); })
内容的提问来源于stack exchange,提问作者M. Al Jumaily
相关产品推荐
相关产品推荐

