Firestore查询难题:按归档状态筛选含当前用户的聊天
已归档聊天的查询(直接支持)
Firebase 允许针对不同字段使用多个 array-contains 操作符,所以你可以直接组合两个条件来查询当前用户参与且已归档的聊天:
const archivedRoomsQuery = query( roomsRef, where(USERS_PATH, 'array-contains', currentUserId), where(ARCHIVE_USERS_FIELD, 'array-contains', currentUserId), orderBy(LAST_UPDATED_FIELD, 'desc'), limit(roomsPerPage), startAfter(lastArchivedRoom) );
这个查询完全合法,两个 array-contains 分别作用于 chatUsers 和 archivedChat 两个独立数组字段,Firebase 支持这种组合条件。
未归档聊天的查询(需要调整数据结构)
由于 Firebase 没有 array-not-contains 操作符,且 not-in 是匹配值不在指定值列表里(而非数组字段不包含某个值),直接用原结构无法实现高效查询,推荐以下两种调整方案:
方案1:新增辅助数组字段
给每个聊天文档添加 activeUsers 数组,存储未归档该聊天的用户ID。当用户归档聊天时,从 activeUsers 移除该ID并添加到 archivedChat;取消归档时反向操作。
未归档聊天的查询可复用 array-contains 组合:
const activeRoomsQuery = query( roomsRef, where(USERS_PATH, 'array-contains', currentUserId), where('activeUsers', 'array-contains', currentUserId), orderBy(LAST_UPDATED_FIELD, 'desc'), limit(roomsPerPage), startAfter(lastActiveRoom) );
优点是查询效率高,和已归档查询逻辑统一;缺点是写操作时需要维护两个数组的同步。
方案2:改用Map结构存储归档状态
将 archivedChat 数组替换为 archivedBy Map对象,结构示例:
{ "chatUsers": [1,2,3,4,5], "archivedBy": { "1": true, "2": true } }
键为用户ID,值为 true 表示该用户已归档聊天;未归档用户在Map中无对应键(或值设为 false)。
未归档聊天的查询代码:
const activeRoomsQuery = query( roomsRef, where(USERS_PATH, 'array-contains', currentUserId), where(`archivedBy.${currentUserId}`, '==', null), orderBy(LAST_UPDATED_FIELD, 'desc'), limit(roomsPerPage), startAfter(lastActiveRoom) );
如果用户取消归档后将值设为 false,则查询条件改为 where(archivedBy.${currentUserId}, '!=', true)。这种方式无需维护双数组,写操作更简洁。
临时替代方案:前端过滤
如果暂时不想修改数据结构,可先查询所有当前用户参与的聊天(仅用 chatUsers array-contains),再在前端过滤掉已归档条目。即便有上千条聊天,分页加载(如每次20条)的情况下,前端过滤的性能开销可忽略,适合快速迭代场景。
内容的提问来源于stack exchange,提问作者VinnieS

