Kotlin中Firebase实时数据库迁移至Firestore的QuerySnapshot使用问题
解决Firestore QuerySnapshot遍历与用户筛选迁移问题
刚从Firebase实时数据库转Firestore确实会有逻辑上的适配调整,我一步步帮你把原来的功能迁移过来,顺便给你优化下实现方式~
先搞懂QuerySnapshot怎么处理文档
Firestore的QuerySnapshot是多个文档的集合容器,你可以通过它的documents属性拿到所有匹配的DocumentSnapshot列表,遍历每个文档后,就能像操作实时数据库的DataSnapshot那样获取字段值了。举个基础遍历例子:
snapshot?.documents?.forEach { document -> val userId = document.id // 对应原来的dataSnapshot.key val name = document.getString("name") ?: "" // 其他字段的读取逻辑同理 }
迁移你的用户筛选逻辑到Firestore
结合你原来的实时数据库业务逻辑,我把getUsersInfo函数重写为适配Firestore的版本:
fun getUsersInfo() { val currentUId = FirebaseAuth.getInstance().uid ?: return val userInterest = "你的用户兴趣值" // 替换成你实际的userInterest变量 usersDb!!.addSnapshotListener(EventListener<QuerySnapshot> { snapshot, e -> if (e != null) { Log.d(TAG, "Listen failed.", e) return@EventListener } snapshot?.let { querySnapshot -> // 先清空旧数据,避免重复添加 rowItems.clear() querySnapshot.documents.forEach { document -> val userId = document.id // 跳过当前用户自己 if (userId == currentUId) return@forEach // 检查性别是否符合要求 val sex = document.getString("sex") ?: "" if (sex != userInterest && userInterest != "Both") return@forEach // 检查是否已经和当前用户建立过连接(nope或yeps) // 假设你的connections是文档内的Map字段,结构为:connections.nope.{userId}: true val connections = document.getMap<String, Map<String, Boolean>>("connections") ?: emptyMap() val hasNope = connections["nope"]?.containsKey(currentUId) == true val hasYep = connections["yeps"]?.containsKey(currentUId) == true if (hasNope || hasYep) return@forEach // 提取用户信息 val name = document.getString("name") ?: "" val age = document.getString("age") ?: "" val job = document.getString("job") ?: "" val about = document.getString("about") ?: "" val profileImageUrl = document.getString("profileImageUrl") ?: "default" // 创建并添加到列表(避免重复) val item = cardObject(userId, name, age, about, job, profileImageUrl) if (!rowItems.any { it.userId == item.userId }) { rowItems.add(item) } } // 更新适配器刷新UI cardAdapter?.notifyDataSetChanged() } }) }
更优的Firestore实现建议
上面的代码是直接迁移你的原有逻辑,但Firestore的核心优势是服务端查询过滤,能减少客户端计算量和带宽消耗,推荐你调整成以下方式:
1. 用Firestore查询提前过滤基础条件
先在服务端排除当前用户、筛选性别符合的用户,减少返回的数据量:
val baseQuery = usersDb!! .whereNotEqualTo("__name__", currentUId) // 用__name__匹配文档ID,排除当前用户 .whereIn("sex", if (userInterest != "Both") listOf(userInterest) else listOf("Male", "Female") // 兴趣为Both时返回所有性别 )
2. 连接状态的优化处理
如果你的connections是子集合(每个用户文档下有connections/nope和connections/yeps子集合),可以用exists查询提前过滤:
val finalQuery = baseQuery .whereNotExists("connections/nope/$currentUId") .whereNotExists("connections/yeps/$currentUId")
首次运行时Firestore会提示你创建对应的索引,跟着控制台提示操作即可。
如果connections是文档内的Map字段,可直接针对Map键做过滤:
val finalQuery = baseQuery .whereNotEqualTo("connections.nope.$currentUId", true) .whereNotEqualTo("connections.yeps.$currentUId", true)
最后把finalQuery传入addSnapshotListener即可,服务端会直接返回符合所有条件的用户,客户端只需要处理结果就行,效率会提升很多~
内容的提问来源于stack exchange,提问作者sykezlol
相关产品推荐
相关产品推荐

