You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中为Firestore实现多WhereNotIn查询?

解决Firestore多条件WhereNotIn查询的限制问题

Firestore确实只允许单个whereNotIn查询,无法直接链式调用多个。针对你需要同时排除被屏蔽用户和日记的场景,可通过以下方式实现需求:

方案一:客户端二次过滤(最直接)

先通过单个whereNotIn过滤掉其中一类数据,再在客户端对结果进行二次过滤,排除另一类不符合条件的文档。建议优先过滤数据量更大的集合,减少客户端需要处理的数据量。

修改你的代码如下:

var storeBuilder: Query?

userDB.document("$userId")
    .get()
    .addOnSuccessListener { document ->
        val blockedUser = document.data?.getValue("blockedUser") as? ArrayList<String> ?: arrayListOf()
        val blockedDiary = document.data?.getValue("blockedDiary") as? ArrayList<String> ?: arrayListOf()

        when {
            blockedUser.isNotEmpty() && blockedDiary.isNotEmpty() -> {
                // 先通过whereNotIn过滤被屏蔽的日记
                diaryDB.whereNotIn("diaryId", blockedDiary)
                    .get()
                    .addOnSuccessListener { querySnapshot ->
                        // 客户端过滤掉被屏蔽用户的日记
                        val filteredDiaries = querySnapshot.documents.filter { doc ->
                            !blockedUser.contains(doc.getString("userId"))
                        }
                        // 处理filteredDiaries数据
                    }
            }
            blockedUser.isNotEmpty() -> {
                storeBuilder = diaryDB.whereNotIn("userId", blockedUser)
                // 执行查询并处理结果
            }
            blockedDiary.isNotEmpty() -> {
                storeBuilder = diaryDB.whereNotIn("diaryId", blockedDiary)
                // 执行查询并处理结果
            }
            else -> {
                storeBuilder = diaryDB
                // 执行查询并处理结果
            }
        }
    }

方案二:拆分查询合并结果(适用于列表元素过多的情况)

如果blockedUser或blockedDiary的元素数量超过50(FirestorewhereNotIn的上限),需要将列表拆分为多个子列表,分别执行查询后合并结果,再进行客户端过滤。

示例(以拆分blockedDiary为例):

fun splitList(list: List<String>, chunkSize: Int = 50): List<List<String>> {
    return list.chunked(chunkSize)
}

// 在需要处理的地方:
val splitBlockedDiaries = splitList(blockedDiary)
val tasks = mutableListOf<Task<QuerySnapshot>>()

splitBlockedDiaries.forEach { chunk ->
    tasks.add(diaryDB.whereNotIn("diaryId", chunk).get())
}

Tasks.whenAllSuccess<QuerySnapshot>(tasks)
    .addOnSuccessListener { results ->
        val allDocuments = results.flatMap { it.documents }
        // 再过滤blockedUser
        val filteredDiaries = allDocuments.filter { doc ->
            !blockedUser.contains(doc.getString("userId"))
        }
        // 处理最终数据
    }

注意事项

  • 客户端过滤会增加本地数据处理的开销,若数据集过大,建议结合分页查询减少单次加载的数据量。
  • 如果对数据实时性要求高,可以考虑使用Cloud Functions在后端完成过滤逻辑,客户端直接获取处理后的结果。

内容的提问来源于stack exchange,提问作者Hyejung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:35:21