Kotlin中FireStore空数组的whereNotIn查询问题及屏蔽校验方案咨询
嗨,我来帮你搞定这个Firestore查询的问题~
首先咱们得搞清楚为什么会报错:Firestore的whereNotIn方法有个硬性要求——传入的数组不能是空的,哪怕你是想用空数组表示“没有需要排除的内容”也不行,这是它API的限制,所以当你的blockedUser或blockedDiary是空数组时,直接加whereNotIn就会触发那个错误。
解决当前报错的直接方案
其实很简单,咱们在构建查询的时候加个判断:只有当数组不为空的时候,才添加对应的whereNotIn过滤条件。如果数组是空的,就跳过这个条件(相当于不对这个维度做过滤,正好符合“没屏蔽任何内容就不排除”的需求)。修改后的代码大概是这样:
userDB.document("$userId") .get() .addOnSuccessListener { document -> // 做null安全处理,避免空指针或类型转换异常 val blockedUser = document.data?.getValue("blockedUser") as? ArrayList<String> ?: arrayListOf() val blockedDiary = document.data?.getValue("blockedDiary") as? ArrayList<String> ?: arrayListOf() // 先初始化基础查询 var diaryQuery = diaryDB // 只有当屏蔽用户数组非空时,才添加过滤条件 if (blockedUser.isNotEmpty()) { diaryQuery = diaryQuery.whereNotIn("userId", blockedUser) } // 同理处理屏蔽日记的条件 if (blockedDiary.isNotEmpty()) { diaryQuery = diaryQuery.whereNotIn("diaryId", blockedDiary) } // 执行最终查询 diaryQuery.get() .addOnSuccessListener { documents -> // 这里处理你的查询结果 } }
关于数据结构的优化建议
你当前用数组存blockedUser和blockedDiary的方案其实挺合理的,适合大多数场景。不过如果未来用户屏蔽的数量可能超过50个(Firestore的in/not_in最多支持50个元素),那可以考虑换一种存储方式:
比如把blockedUser改成Map类型,键是被屏蔽的用户ID,值设为true(比如blockedUser: {"user_123": true, "user_456": true})。这种方式存储时可以快速判断某个用户是否被屏蔽,但查询时还是需要先把Map的键提取成数组再用whereNotIn,本质上和数组方案的查询逻辑差不多。
如果屏蔽数量特别大,那可能需要借助Firebase云函数来做服务器端的过滤,或者给日记文档添加额外的标记,但一般来说,普通用户的屏蔽数量不会到50个,所以当前的数组方案完全够用。
备注:内容来源于stack exchange,提问作者Hyejung

