как проверить пути к документам в firestore?

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

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

                getSchoolDocumentID { (schoolDocID) in
                if let schID = schoolDocID {
                    self.db.document("school_users/\(schID)/events/\(self.selectedEventID!)").getDocument { (documentSnapshot, error) in
                        if let error = error {
                            print("There was an error fetching the document: \(error)")
                        } else {

                            guard let docSnap = documentSnapshot!.get("purchased") else {
                                return
                            }
                            if docSnap as! Bool == true {
                                self.viewPurchaseButton.isHidden = false
                                self.cancelPurchaseButton.isHidden = false
                                self.creditCard.isHidden = true
                                self.purchaseTicketButton.isHidden = true

                            } else {
                                self.creditCard.isHidden = false
                                self.purchaseTicketButton.isHidden = false
                            }
                        }
                    }
                }
            }

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

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

getEventsBoughtEventID { (eventBought) in
        if let idOfEventBought = eventBought {
            
            let docPath = self.db.document("student_users/\(self.user?.uid)/events_bought/\(idOfEventBought)")
            
            if docPath.path.isEmpty {
                self.creditCard.isHidden = false
                self.purchaseTicketButton.isHidden = false
            } else {
                self.db.document("student_users/\(self.user?.uid)/events_bought/\(idOfEventBought)").getDocument { (documentSnapshot, error) in
                    if let error = error {
                        print("There was an error trying to fetch this document: \(error)")
                    } else {
                        guard let docSnapEventName = documentSnapshot!.get("event_name") else {
                            return
                        }
                        
                        if docSnapEventName as! String == self.selectedEventName! {
                            self.viewPurchaseButton.isHidden = false
                            self.cancelPurchaseButton.isHidden = false
                            self.creditCard.isHidden = true
                            self.purchaseTicketButton.isHidden = true
                        }
                    }
                }
            }
        }
    }

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


person dsonawave    schedule 10.02.2021    source источник


Ответы (2)


Итак, я наконец понял, как это сделать. Это было 4 часа работы и борьбы, но я получил это, конечно, с несколькими ошибками. Итак, я выяснил, что причина сбоя моего приложения заключалась не только в сегментах пути, но и в том, что idOfEventBought не существовал для некоторых событий, потому что эти события еще не были приобретены, и что не было подколлекции с именем events_bought даже создано еще.

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

 db.document("student_users/\(result?.user.uid)/events_bought/test_document").setData(["test": "test"])

Эта строка кода позволила мне придумать следующий метод, который может проверить, было ли мероприятие куплено или нет.

func checkIfUserMadePurchase(shouldBeginQuery: Bool) -> Bool {
    if shouldBeginQuery == true {
        
        getEventsBoughtEventID { (eventBought) in
            if let idOfEventBought = eventBought {

                self.docListener = self.db.document("student_users/\(self.user?.uid)/events_bought/\(idOfEventBought)").addSnapshotListener(includeMetadataChanges: true) { (documentSnapshot, error) in

                    if let documentSnapshot = documentSnapshot {

                        if documentSnapshot.exists {
                            self.creditCard.isHidden = true
                            self.purchaseTicketButton.isHidden = true
                            self.viewPurchaseButton.isHidden = false
                            self.cancelPurchaseButton.isHidden = false
                            
                        }
                    }
                }
            }
         
        }
        return true
    
 } else {
    creditCard.isHidden = false
    purchaseTicketButton.isHidden = false
    viewPurchaseButton.isHidden = true
    cancelPurchaseButton.isHidden = true
    return false
    }
}

Я использовал этот метод, чтобы проверить, было ли мероприятие приобретено, и не отображаются ли нужные кнопки.

Затем я вызываю его, когда нажимается кнопка покупки в моем UIAlertController.

       self.checkIfUserMadePurchase(shouldBeginQuery: true)

Наконец, я создаю функцию, которая использует логику для проверки того, было ли событие куплено, и, если оно было куплено, делаю что-то конкретное. Затем я вызываю эту функцию в viewDidLoad(), viewWillAppear() и viewWillDisappear().

func purchasedStatusVerification() {
    db.collection("student_users/\(user?.uid)/events_bought").whereField("event_name", isEqualTo: self.selectedEventName!).getDocuments { (querySnapshot, error) in
        if let querySnapshot = querySnapshot {
            if querySnapshot.isEmpty {
                self.checkIfUserMadePurchase(shouldBeginQuery: false)
            } else {
                self.checkIfUserMadePurchase(shouldBeginQuery: true)
            }
        }
    }

}

Со всем этим мое приложение работает так, как я хочу, я могу успешно приобрести мероприятие, и оно не будет отображаться в другой учетной записи пользователя. Есть несколько ошибок, например, когда создается новое событие, отображаются неправильные и правильные кнопки, но неправильные кнопки исчезают после входа в систему и выхода из нее. Кроме того, метод isHidden() движется довольно медленно: когда я загружаю vc, а событие имеет статус купленного, purchaseTicketButton присутствует на долю секунды, а затем исчезает, что довольно раздражает. В общем, я разобрался и постараюсь улучшить его к моменту производства.

person dsonawave    schedule 11.02.2021
comment
Вы захотите исправить это user?.uid, как будто пользователь равен нулю, ваше приложение выйдет из строя; защитите свой код, безопасно распаковав опции. Вторая проблема заключается в том, что этот оператор return true будет выполняться перед кодом в закрытии firebase, что означает, что он будет почти каждый раз возвращать истину. Firebase работает асинхронно, а код работает быстрее, чем в Интернете, что вызывает долгосрочные периодические проблемы. Наконец, у вас есть код, чтобы узнать, было ли мероприятие приобретено, но это зависит от того, существует ли событие. Кажется, что если его нет, значит, его явно не покупали. - person Jay; 11.02.2021
comment
Большой. Итак, вместо того, чтобы просто указывать на проблемы, можете ли вы добавить ответ и объяснить, что мне нужно делать и где в моем коде, чтобы мне не пришлось сталкиваться с этими проблемами в будущем? Кроме того, пользователь буквально не может быть нулевым, после регистрации путь создается, и он создается с дополнительным идентификатором пользователя, невозможно войти в приложение без аутентификации и фактического создания учетной записи, поэтому я не Я понимаю, как пользователь может быть нулевым. @Jay - person dsonawave; 11.02.2021
comment
Пользователь может быть нулевым по ряду причин. См. Примечание здесь. Публикация дополнительного ответа будет дубликатом множества других ответов. Вы можете увидеть это или выполните поиск по запросу Firebase Async, чтобы получить кучу Примеры. Другая проблема была просто логической вещью, с которой вы можете работать. - person Jay; 11.02.2021
comment
Хорошая работа по поиску решения! Можете ли вы принять свой ответ? Это сделает его более заметным и поможет кому-то с той же проблемой, когда вы найдете решение. Спасибо! - person llompalles; 19.02.2021
comment
Привет, @llompalles, спасибо, что сделали это сейчас. - person dsonawave; 19.02.2021

В пути к документу "student_users/\(self.user?.uid)/events_bought/\(idOfEventBought)" вы используете self.user?. ? создаст student_users/Optional(uid)/events_bought строку, но не student_users/uid/events_bought строку. Используйте self.user! или if let user = self.user {

person Aznix    schedule 10.02.2021
comment
Я должен, иначе путь будет неправильным, и код выйдет из строя. Я не думаю, что проблема в пути, путь работает нормально. @Aznix - person dsonawave; 11.02.2021
comment
Таким образом, с \(self.user?.uid) ваш путь будет неправильным - person Aznix; 11.02.2021
comment
Нет, это правильно. Посмотрите на путь в моей базе данных Firestore: /student_users/Optional("UhRGfXkk3cbCQt02S6q54B0uydE3")/events_bought/cg3bQv3hRoucAnnuDEBV. @Aznix - person dsonawave; 11.02.2021
comment
Истинный путь может быть /student_users/UhRGfXkk3cbCQt02S6q54B0uydE3/events_bought/cg3bQv3hRoucAnnuDEBV. Optional не является нежелательным в пути - person Aznix; 11.02.2021
comment
Брат, к настоящему моменту я использовал опции в своих путях примерно в 20 запросах Firestore, и все они работают идеально. @Aznix - person dsonawave; 11.02.2021