Приложение для чата Firestore, отображающее ошибку отправленных пользователей

#swift #firebase #google-cloud-firestore

#swift #firebase #google-облако-firestore

Вопрос:

Я добавил чат / обмен сообщениями в свое приложение. Я могу зайти в профиль пользователя, выбрать сообщение и отправить им сообщение. Я также добавил вкладку, на которой отображаются все пользователи, которым я отправил сообщение, в виде таблицы, и вы можете щелкнуть пользователя и просмотреть сообщения между вами и ними.

Проблема возникает, когда я открываю эту вкладку, чтобы увидеть пользователей, которым я отправил сообщения, когда я отправил сообщения более чем 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)
        }
    }
    
}

  

Вот изображение ошибки, которую я получаю

Вот изображение моей базы данных Firestore

Ответ №1:

Сообщение об ошибке сообщает вам, что Firestore не поддерживает более 10 элементов в ids массиве, который вы передаете этому фильтру запросов:

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

Согласно документации для такого рода запросов:

Обратите внимание на следующие ограничения для in и array-contains-any:

  • в и массив-содержит-любой поддерживает до 10 значений сравнения.

Если вам нужно больше 10, вам нужно будет объединить их в несколько запросов.

Комментарии:

1. привет, Даг, большое тебе спасибо!! Я действительно ценю это. есть ли другой способ сделать это, который вы бы порекомендовали по сравнению с тем, как я сейчас это делаю?

2. Мое предложение содержится в последнем предложении.