【问题标题】:Firestore chat application displaying messaged users errorFirestore 聊天应用程序显示消息用户错误
【发布时间】:2020-09-04 04:10:26
【问题描述】:

我已将聊天/消息添加到我的应用程序中。我可以转到用户个人资料,选择消息并向他们发送消息。 我还添加了一个选项卡,在表格视图中显示我发送消息的所有用户,您可以单击用户并查看您和他们之间的消息。

当我向超过 10 个用户发送消息时,当我打开此选项卡以查看我发送消息的用户时,就会出现此问题。模拟器崩溃,我收到此错误:

“线程 1:异常:”无效查询。 'in' 过滤器支持值数组中最多 10 个元素。"
这是我的代码:


import UIKit
import FirebaseFirestore

class MessagingVC: UIViewController {
        
    @IBOutlet weak var tableView: UITableView! { didSet {
        tableView.tableFooterView = UIView()
        tableView.contentInset.top = 10
        }}
    @IBOutlet weak var noDataLabel: UILabel!
    
    private let db = Firestore.firestore()
    
    var users = [AppUser]()
    
    var user: AppUser {
        return UserManager.currentUser!
    }
    
    private var lastMessageDict: [String: Date]?
    private var unreadMessageDict: [String: Bool]?
    
    var chatListener: ListenerRegistration?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        getChats()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        noDataLabel.isHidden = true
        
        // remove any blocked users when entering the screen.
        users.removeAll() { self.user.blockedUsers?.contains($0.uid) == true }

        // filter hidden users
        users = users.filter { $0.isHidden ?? false == false }

        tableView.reloadData()

  //     getChats()
    }
    
    // Get all users id that the current user has been chating with.
    func getChats() {
        let chatCollection = db.collection("chat")
        chatListener = chatCollection.whereField("participants", arrayContains: user.uid).addSnapshotListener { [unowned self] (querySnapshot, error) in
            guard error == nil else {
                print(error!.localizedDescription)
                return
            }
            
            var userChatIds = [String]()
            self.lastMessageDict = [String: Date]()
            self.unreadMessageDict = [String: Bool]()
            for chat in querySnapshot?.documents ?? [] {
                let chatData = chat.data()
                if let participants = chatData["participants"] as? [String] {
                    for particiant in participants {
                        if particiant != self.user.uid,
                            !(self.user.blockedUsers?.contains(particiant) == true),
                            !userChatIds.contains(particiant) {
                            userChatIds.append(particiant)
                            if let lastMessageDate = chatData["last message"] as? Timestamp {
                                self.lastMessageDict![particiant] = lastMessageDate.dateValue()
                            }
                            if let unreadMessageDict = chatData["unread message"] as? [String: Bool],
                                let unreadMesage = unreadMessageDict[self.user.uid] {
                                self.unreadMessageDict![particiant] = unreadMesage
                            }
                        }
                    }
                }
            }
            
            if !userChatIds.isEmpty {
                self.getChatsInfo(chatIds: userChatIds)
            } else {
                self.tableView.reloadData()
                self.noDataLabel.isHidden = self.users.count > 0
            }
            
        }
    }
    
    func getChatsInfo(chatIds: [String]) {
        getUsersForChat(chatIds) { (users, error) in
            guard error == nil else {
                print(error?.localizedDescription ?? "")
                return
            }
            
            for user in users {
                if let index = self.users.firstIndex(of: user) {
                    self.users[index] = user
                } else {
                    self.users.append(user)
                }
            }
            
      //      self.users = users
            
            self.users.sort { (first, second) -> Bool in
                let firstDate = self.lastMessageDict?[first.uid]
                let secondDate = self.lastMessageDict?[second.uid]
                if firstDate == nil { return false }
                else if secondDate == nil { return true }
                else {
                    return firstDate! > secondDate!
                }
            }

            self.users = self.users.filter { $0.isHidden ?? false == false }
            self.tableView.reloadData()
            self.noDataLabel.isHidden = self.users.count > 0
        }
    }
    
    func getUsersForChat(_ ids: [String], completion:@escaping (_ users: [AppUser], _ error: Error?)->()) {
                
        var allUsers = [AppUser]()
        
        let allids = self.users.map { $0.uid }
        let ids = ids.filter { !allids.contains($0) }
        
        if ids.count == 0 {
            completion(allUsers, nil)
            return
        }
        
        var error: Error?
        let userCollection = db.collection("users")
        
        let dispatchGroup = DispatchGroup()
        dispatchGroup.enter()
        userCollection.whereField("uid", in: ids).getDocuments {querySnapshot,err in
            error = err
            var users = [AppUser]()
            for document in querySnapshot?.documents ?? [] {
                if let restaurant = Restaurant(snapshot: document) {
                    users.append(restaurant)
                }
            }
            allUsers.append(contentsOf: users)
            dispatchGroup.leave()
        }
        
        dispatchGroup.enter()
        let userCollection2 = db.collection("users2")
        userCollection2.whereField("uid", in: ids).getDocuments {querySnapshot,err in
            error = err
            var users = [AppUser]()
            for document in querySnapshot?.documents ?? [] {
                if let user = AppUser(snapshot: document) {
                    users.append(user)
                }
            }
            allUsers.append(contentsOf: users)
            dispatchGroup.leave()
        }
        
        dispatchGroup.notify(queue: DispatchQueue.main) {
            completion(allUsers, error)
        }

    }
    
    deinit {
        chatListener?.remove()
    }
    
}

extension MessagingVC: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return users.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessagingTableViewCell
        
        let user = users[indexPath.row]
        cell.nameLabel.text = user.firstName + " " + user.lastName

        if let unreadMessage = unreadMessageDict?[user.uid],
            unreadMessage == true {
            cell.unreadMessageIndicatorLabel.isHidden = false
        } else {
            cell.unreadMessageIndicatorLabel.isHidden = true
        }
        
        cell.photoImageView.image = nil
        user.getProfileImage { (image) in
            DispatchQueue.main.async {
                if let cell = tableView.cellForRow(at: indexPath) as? MessagingTableViewCell {
                    cell.photoImageView.image = image
                }
            }
        }

        if let rest = user as? Restaurant {
            cell.categoryImageView.image = UIImage(named: rest.Categories1)
        }
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let user = users[indexPath.row]
//        unreadMessageDict?[user.uid] = false
        performSegue(withIdentifier: "messagingToChatSegue", sender: user)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "messagingToChatSegue" {
            let chatVC = segue.destination as! ChatViewController
            let otherUser = sender as! AppUser
            chatVC.currentUser = user
            chatVC.otherUser = otherUser
            chatVC.channelId = ClickedResturantVC.generateIdForMessages(user1Id: user.uid, user2Id: otherUser.uid)
        }
    }
    
}

Here is a picture of the error I am getting

Here is a picture of my Firestore database

【问题讨论】:

    标签: swift firebase google-cloud-firestore


    【解决方案1】:

    错误消息告诉您,Firestore 不支持您传递给此查询过滤器的 ids 数组中的 10 个以上的项目:

    userCollection.whereField("uid", in: ids)
    

    根据documentation 进行此类查询:

    注意以下对 in 和 array-contains-any 的限制:

    • in 和 array-contains-any 支持最多 10 个比较值。

    如果您需要超过 10 个,则需要将它们批处理到多个查询中。

    【讨论】:

    • 嘿,道格,非常感谢!对此,我真的非常感激。与我目前的做法相比,您会推荐另一种方法吗?
    • 我的建议在最后一句。
    猜你喜欢
    • 2019-12-20
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 2014-01-13
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多