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

如何在Firebase users集合查询中排除已拉黑的指定用户ID

解决方案

因为Firebase Realtime Database原生不支持「排除指定值」的查询条件,所以我们采用「先拉取拉黑名单、再过滤用户查询结果」的方案实现需求,具体修改如下:

前置准备

先在当前页面的类中新增一个属性,用来存储所有已拉黑的用户ID,Set类型的查询效率远高于数组,适合频繁判断包含关系:

// 存储当前登录用户拉黑的所有用户ID
private var blockedUids: Set<String> = []

修改后的完整拉取逻辑

func fetchUsers() {
    guard let currentUid = Auth.auth().currentUser?.uid else { return }
    // 首次加载时先拉取所有拉黑用户ID,再查询用户列表
    if userCurrentKey == nil {
        BLOCKED_USERS.child(currentUid).observeSingleEvent(of: .value) { [weak self] snapshot in
            guard let self = self else { return }
            // 清空旧的拉黑ID,重新存入最新的所有拉黑ID
            self.blockedUids.removeAll()
            for child in snapshot.children {
                guard let childSnap = child as? DataSnapshot else { continue }
                self.blockedUids.insert(childSnap.key)
            }
            // 拿到所有拉黑ID后再执行首次用户查询
            USER_REF.queryLimited(toLast: 10).observeSingleEvent(of: .value) { snapshot in
                guard let first = snapshot.children.allObjects.first as? DataSnapshot,
                      let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
                // 临时数组存储本次查询到的合法用户,避免频繁刷新列表
                var tempUsers: [User] = []
                let group = DispatchGroup()
                allObjects.forEach { snap in
                    let uid = snap.key
                    // 过滤掉当前用户自己、以及已拉黑的用户
                    guard uid != currentUid, !self.blockedUids.contains(uid) else { return }
                    group.enter()
                    Database.fetchUser(with: uid) { user in
                        tempUsers.append(user)
                        group.leave()
                    }
                }
                // 所有用户信息拉取完成后统一刷新列表
                group.notify(queue: .main) {
                    self.users.append(contentsOf: tempUsers)
                    self.tableView.reloadData()
                    self.userCurrentKey = first.key
                }
            }
        }
    } else {
        // 分页加载逻辑,同样增加过滤规则
        USER_REF.queryOrderedByKey().queryEnding(atValue: userCurrentKey).queryLimited(toLast: 5).observeSingleEvent(of: .value) { [weak self] snapshot in
            guard let self = self,
                  let first = snapshot.children.allObjects.first as? DataSnapshot,
                  var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
            // 移除分页边界的重复用户
            allObjects.removeAll(where: { $0.key == self.userCurrentKey })
            var tempUsers: [User] = []
            let group = DispatchGroup()
            allObjects.forEach { snap in
                let uid = snap.key
                // 过滤规则和首次加载保持一致
                guard uid != currentUid, !self.blockedUids.contains(uid) else { return }
                group.enter()
                Database.fetchUser(with: uid) { user in
                    tempUsers.append(user)
                    group.leave()
                }
            }
            group.notify(queue: .main) {
                self.users.append(contentsOf: tempUsers)
                self.tableView.reloadData()
                self.userCurrentKey = first.key
            }
        }
    }
}

关键修改说明

  • 把原来的childAdded监听改为单次value监听,一次性拉取所有拉黑ID,避免有多个拉黑用户时重复触发用户列表查询
  • 所有用户查询结果都先经过两层过滤:排除当前登录用户自己、排除已拉黑的用户
  • 用DispatchGroup统一管理异步用户信息拉取,所有用户数据拉取完成后才刷新列表,避免频繁刷新带来的性能问题
  • 首次加载和分页加载的过滤逻辑完全统一,不会出现分页时漏过滤的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 20:48:02