Firestore多whereArrayContains查询不支持的临时替代方案咨询
我懂你的痛点!Firestore确实还不支持多个whereArrayContains查询,不过在官方推出正式解决方案前,咱们有几个靠谱的临时办法可以试试:
临时替代方案
1. 客户端过滤(简单但需注意性能)
如果你的服务文档数量不算特别多,可以先只用一个whereArrayContains查询获取部分结果,然后在客户端内存里过滤剩下的条件。比如先查所有在Location-1提供的服务,再在客户端筛选出对Seller开放的:
fun services(at: String, by: UserRole) = firestore().collection(Refs.SERVICE_REF) .whereArrayContains(Fields.SERVICEABLE_AT, at) .get() .addOnSuccessListener { documents -> val filteredServices = documents.mapNotNull { doc -> val accessibleRoles = doc.get(Fields.ACCESSIBLE_BY) as? List<UserRole> if (accessibleRoles?.contains(by) == true) { doc.toObject(Service::class.java) } else { null } } // 处理过滤后的结果 }
注意:如果数据量很大,这种方法会拉取过多不必要的数据,增加带宽消耗和客户端内存压力,只适合小数据集场景。
2. 重构数据结构(推荐,适合长期使用)
调整你的文档结构,把需要组合查询的数组条件转化为映射(Map)或复合字段,这样就能用whereEqualTo来查询。比如:
把原来的两个数组,改成一个locationRolePairs字段,存储包含地点和角色组合的字符串列表:
// 示例文档结构 data class Service( // 其他字段... val locationRolePairs: List<String> = listOf("Location-1:Seller", "Location-1:Customer") )
查询的时候就可以用单个whereArrayContains:
fun services(at: String, by: UserRole) = firestore().collection(Refs.SERVICE_REF) .whereArrayContains(Fields.LOCATION_ROLE_PAIRS, "$at:$by")
这种方法的好处是完全在服务端完成查询,性能更优,但需要你更新现有数据的结构,并且在新增服务的时候要正确生成这些组合字段。
3. 使用Cloud Functions做服务端过滤
如果客户端过滤性能不够,又不想改数据结构,可以借助Cloud Functions,在服务端先执行第一个whereArrayContains查询,然后在云函数里过滤第二个条件,再返回结果给客户端。这样客户端只需要接收最终过滤后的结果,减少带宽占用:
// 云函数示例(Node.js) exports.getFilteredServices = functions.https.onCall(async (data, context) => { const { at, by } = data; const snapshot = await admin.firestore() .collection('service') .where('serviceableAt', 'array-contains', at) .get(); const filtered = []; snapshot.forEach(doc => { const data = doc.data(); if (data.accessibleBy.includes(by)) { filtered.push({ id: doc.id, ...data }); } }); return filtered; });
然后在客户端调用这个云函数:
val functions = FirebaseFunctions.getInstance() val data = hashMapOf("at" to "Location-1", "by" to "Seller") functions.getHttpsCallable("getFilteredServices") .call(data) .addOnSuccessListener { result -> val services = result.data as List<Map<String, Any>> // 处理结果 }
内容的提问来源于stack exchange,提问作者Chandra Sekhar
相关产品推荐
相关产品推荐

