【问题标题】:Firestore not recognizing fields properlyFirestore 无法正确识别字段
【发布时间】:2021-05-13 11:39:43
【问题描述】:

所以我的目标是在加载表格视图单元格的 detailsVC 并且未购买的事件显示不同的按钮时让购买的事件显示某些按钮。所以我在这种情况下所做的是对集合路径中的文档进行查询调用,字段为purchased:true,如果有错误,处理它,但如果没有,显示已购买事件的按钮。

    override func viewDidLoad() {
    super.viewDidLoad()
    
    
    viewPurchaseButton.isHidden = true
    cancelPurchaseButton.isHidden = true
   
    
    getSchoolDocumentID { (id) in
        if let ident = id {
            self.db.collection("school_users/\(ident)/events").whereField("purchased", isEqualTo: true).getDocuments { (querySnapshot, error) in
                if let error = error {
                    print("There was an error fetching the docs: \(error)")
                } else {
                    self.viewPurchaseButton.isHidden = false
                    self.cancelPurchaseButton.isHidden = false
                    self.purchaseTicketButton.isHidden = true
                    self.creditCard.isHidden = true
                }
            }
        }
        
    }

所以我运行这个认为它会起作用,我在集合中只有 4 个文档中的 1 个文档具有字段 purchased 等于 true,所以当我单击该字段为 @ 的单元格时,我预计987654326@ 在我的 tableVC 中,详细信息 VC 将显示正确的按钮。 detailsVC 显示了正确的按钮,但是当我离开 VC 并单击另一个具有purchased 字段为false 的单元格时,我很困惑为什么会出现这些按钮。如果有人可以向我解释为什么会发生这种情况或指出我的代码存在问题,那就太好了。

【问题讨论】:

    标签: swift firebase google-cloud-platform google-cloud-firestore querying


    【解决方案1】:

    我相信你假设如果没有找到匹配项,闭包中的代码将不会运行,这是不正确的。

    Firestore 查询闭包将始终运行闭包内的代码,无论是否有结果。

    这是一个示例代码流

    self.db.collection("school_users/\(ident)/events")... { querySnapshot, error
       // handle error
    
      // the below code always runs (unless there was an error handled above)   
      let docs = querySnapshot?.documents
      print(docs!.count) //will print 0 if no results, or the number of results
    }
    

    因此,在您的问题中,只要没有错误并且无论快照的内容如何,​​此代码都会每次运行;

    self.viewPurchaseButton.isHidden = false
    self.cancelPurchaseButton.isHidden = false
    self.purchaseTicketButton.isHidden = true
    self.creditCard.isHidden = true
    

    这样就可以了

    self.db.collection("school_users/\(ident)/events").whereField("purchased", isEqualTo: true).getDocuments { (querySnapshot, error) in
        if let error = error {
            print("There was an error fetching the docs: \(error)")
            return
        }
    
        guard let docs = querySnapshot?.documents else { return }
    
        for doc in docs { //for testing to examine the returned docs, if any
           print(doc)
        }
    
        if docs.count > 0 {
            self.viewPurchaseButton.isHidden = false
            self.cancelPurchaseButton.isHidden = false
            self.purchaseTicketButton.isHidden = true
            self.creditCard.isHidden = true
        }
    }
    

    【讨论】:

    • 由于某种原因,它仍然不起作用。 @Jay
    • 作为一个初学者,我理解了解释并有一种感觉,我也理解了代码,但是应用程序功能的结果完全没有改变。 @Jay
    • @dsonawave 可能存在许多问题,但当您认为没有文档时,您的查询很可能正在返回文档,因此计数大于 0。您可以通过检查 querySnapshot 的内容进行一些故障排除封闭内。我添加了一个只打印这些内容的 for 循环 - 添加该代码并运行您的应用程序。如果您看到打印的内容,那么问题出在您的查询上,并且它在您期望没有结果时返回结果。
    • 好的,所以我添加了 for 循环并将 .data() 添加到文档中,这样我就可以看到实际信息,它打印了一个文档,因为我刚购买了它,这意味着有问题我的查询。我怎么知道我的查询出了什么问题?该路径是正确的,因为我在其他查询中使用了相同的路径并且它符合我的预期,所以我不确定问题到底出在哪里。 @Jay
    • 好吧,我基本上明白发生了什么并且搞砸了,如果有一个或多个文档的字段 purchase = true,那么所有文档都会影响这些方法。我基本上想一一区分,我尝试了 UserDefaults 但它对我想做的事情不起作用,所以我想知道在 Firestore 中是否可行。因此,如果进行了购买,按钮只会显示该文档,而不是全部。在 Firestore 中是否可以通过查询调用实现这一点,还是我会使用不同的东西? @Jay
    【解决方案2】:

    好的,我为此所做的就是重构查询,而不是获取文档,只需获取一个文档。然后我使用了这个功能,它就像美容一样! :)

    override func viewDidLoad() {
        super.viewDidLoad()
        
        viewPurchaseButton.isHidden = true
        cancelPurchaseButton.isHidden = true
        
        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
                        }
                    }
                }
            }
        }
    

    这可以完美地完成工作。

    【讨论】:

    • 答案改变了问题的参数——这很好,但一般方法应该改变。您对我的回答的评论是因此,如果进行了购买,则仅显示该文档的按钮 - 如果是这种情况,您想向集合添加观察者(又名侦听器),这样您就可以数据更改时会通知应用程序。例如当用户进行购买时,它会写入 Firebase,然后通知应用程序(或所有应用程序)购买已完成。修改后的文档会呈现给应用,因此您可以根据更改更新 UI。
    • 是的,我有一个新问题。我正在考虑按照您所说的做,但是如果您将 snapShotListener 添加到查询中,然后调用 updateData() 方法调用,这是我需要对购买字段执行的操作,它会创建一个无限循环。我之前犯过这个错误,并在 1 小时内用完了我的每日 Firestore 读取配额,哈哈。我将发布我的新问题,有机会时看看。谢谢您的帮助。 @Jay
    • 你是对的,但那不是正确的顺序。添加一个侦听器,更新数据,当您收到事件时,更新您的数据源,然后调用 tableView 刷新。例如等到您从 firestore 获取数据并在其关闭时使用新数据更新数据源并刷新 tableView。
    • 这是对这个问题的回答建议还是我最近的回答建议?如果是这个,你可以添加一个代码 sn-p 作为你的答案吗? @Jay
    • 如果是这个,无视问题,查看我最近的,不要加码sn-p。 @Jay
    猜你喜欢
    • 2012-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-05
    • 2013-07-06
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多