Как поймать ошибку, когда коллекция Firestore уже существует?

#swift #firebase #google-cloud-firestore #try-catch

#swift #firebase #google-облако-firestore #попробуйте-поймайте

Вопрос:

Прямо сейчас мое приложение выходит из строя, когда коллекция уже существует в Firebase Firestore. Я хочу перехватить эту ошибку, когда она произойдет, но моя текущая реализация ничего не улавливает, поскольку addSnapshotListener() метод не выдает никаких ошибок.

Текущий код

 let db = Firestore.firestore()
        
        do {
            try db.collection(chatName).addSnapshotListener { (Query, Error) in
                if Error != nil || Query?.documents != nil {
                    let alert = UIAlertController(title: "Chat Name Already Exists", message: "This chat name already exists, try again with a different name", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (UIAlertAction) in
                        alert.dismiss(animated: true, completion: nil)}))
                    AllChatsViewController().present(alert, animated: true)
                    completion()
                }
                else {
                    self.addChatToProfile(withName: chatName) {
                        completion()
                    }
                }
            }
        }
        catch {
            let alert = UIAlertController(title: "Chat Name Already Exists", message: "This chat name already exists, try again with a different name", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (UIAlertAction) in
                alert.dismiss(animated: true, completion: nil)}))
            AllChatsViewController().present(alert, animated: true)
            completion()
        }
  

Ошибка после сбоя приложения

Поток 1: «Недопустимая ссылка на коллекцию. Ссылки на коллекции должны иметь нечетное количество сегментов, но иметь 0»

Как я могу перехватить эту ошибку, чтобы я мог отобразить UIAlertController с ошибкой?

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

1. Мы не знаем, что chatName содержит строка. Можете ли вы включить это в вопрос? Возможно, вы просто захотите добавить print(chatName) прямо перед вызовом firebase, чтобы посмотреть, что это такое. Также используйте только заглавные буквы имен классов и структур . переменные всегда должны быть в нижнем регистре, чтобы избежать путаницы. Поэтому вместо Query, Error этого должно быть query, error

Ответ №1:

Я бы использовал другой подход.

Чтобы проверить, существует ли коллекция, прочитайте эту коллекцию по имени и определите, есть ли какие-либо документы с помощью snapshot.count равно 0

Проблема здесь в том, что коллекция может содержать большой объем данных, и нет причин читать все это или подключать слушателя, поэтому нам нужно использовать известное поле в этой коллекции, чтобы ограничить результаты.

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

Вам понадобится имя коллекции, которую вы хотите протестировать, а затем имя известного поля в этой коллекции для запроса, чтобы ограничить результаты.

Имя поля важно в том смысле, что если коллекция содержит 1 МЛН документов, вы не хотите читать их все — вы просто хотите прочитать один и .OrderBy с ограничением сделает это.

Итак, вот вызывающая функция

 func checkCollection() {
    self.doesCollectionExist(collectionName: "test_collection", fieldName: "msg", completion: { isEmpty in
        if isEmpty == true {
            print("collection does not exist")
        } else {
            print("collection found!")
        }
    })
}
  

а затем функция, которая проверяет, существует ли коллекция, путем чтения одного документа и возвращает false, если нет, true, если это так.

 func doesCollectionExist(collectionName: String, fieldName: String, completion: @escaping ( (Bool) -> Void ) ) {
    let ref = self.db.collection(collectionName)
    let query = ref.order(by: fieldName).limit(toLast: 1)
    query.getDocuments(completion: { snapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }
        
        if snapshot!.count == 0 {
            completion(true)
        } else {
            completion(false)
        }
    })
}
  

Ответ №2:

Эта ошибка не имеет ничего общего с несуществующей коллекцией Ошибка предполагает, что chatName это пустая строка, которая является недопустимым параметром. Вместо того, чтобы перехватывать ошибку, вы должны сначала проверить, что chatName это допустимая строка имени коллекции, прежде чем отправлять ее в Firestore API.

Если вы запрашиваете коллекцию, которая не существует, вы вообще не получите это сообщение об ошибке. Вместо этого вы просто не получите никаких документов в результирующем наборе.

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

1. chatName однако не пусто, полная строка печатается после добавления инструкции print

2. Тогда, что бы это ни было, оно недействительно. Вы должны проверить это, прежде чем передавать его в API. Правила для имен коллекций и документов приведены здесь: firebase.google.com/docs/firestore /…

3. Я пересмотрел вопрос, проблема в том, что коллекция уже существует. В принципе, я хочу проверить, существует ли коллекция. Если это так, я хочу отобразить UIAlertController, но если это не так, я хочу создать коллекцию под этим именем.

4. Вы действительно должны также показать конкретное значение chatName , которое работает не так, как вы ожидаете. Нет операции для проверки, существует ли коллекция. Вы должны фактически запросить его и получить из него документ, чтобы узнать, что он существует. Ваш запрос не выполняется, потому что значение chatName недопустимо.

Ответ №3:

вы сделаете что-то вроде этого:

      Firestore.firestore().collection(chatName).addSnapshotListener { (query, error) in
          if let error = error {
           //in this part you have the error, do something like present alert with error or something you want
           print(error)
           }
          // in this part the success

  

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

1. в этом случае обычно не используйте try catch, вместо этого используйте строку, которую я вам показываю, и она хорошо работает, но это всего лишь рекомендация.