Swift:在Firebase数据库中搜索特定值并找到所有相关数据

时间:2019-02-14 17:07:35

标签: swift firebase firebase-realtime-database

enter image description here enter image description here

我有数据上传到我的数据库。我正在尝试实现搜索功能,该功能可以按名称搜索内容,如果找到该名称,则使用与该名称相对应的数据自动填充文本字段。因此,例如,如果我搜索“ Pepsi Max”,我想在数据库中找到pepsi max,然后显示价格/位置/价格等。

我目前有一个搜索功能,但是只搜索整个数据库并打印所有值。

func searchT() {

    let pub = pubName.text

    print(pub)


    let databaseRef = Database.database().reference().child("Drinks")
    let query = databaseRef.queryOrdered(byChild: "pub").queryStarting(atValue: pub).queryEnding(atValue: "\(String(describing: pub))\\uf8ff")

    query.observeSingleEvent(of: .value) { (snapshot) in
        guard snapshot.exists() != false else { return }
        print(snapshot.value as Any)
        DispatchQueue.main.async {

            guard let dict = snapshot.value as? [String:Any] else {
                print(snapshot)
                return
            }

            let pubName = dict["pub"] as? String
            let pubLocation = dict["location"] as? String
            let price = dict["price"] as? String
            let rating = dict["rating"] as? String
            let comment = dict["comment"] as? String

            self.pubName.text?.append(pubName!)
            self.pubLocation.text?.append(pubLocation!)
            self.price.text?.append(price!)
            self.rating.text?.append(rating!)
            self.comment.text?.append(comment!)

        }
    }
}

您会注意到,在此函数中,我正在搜索数据“ pubName”(我认为我在第一行中设置有误,但不确定如何更正)。

在将textViews设置为值的第一行时,此函数崩溃,因为“解包可选值时为零”

如何通过pubName进行搜索,找到相应的值,然后将文本字段设置为db中与搜索值有关的其余数据。

谢谢,E

1 个答案:

答案 0 :(得分:1)

1。实时数据库

由于您尚未包括数据库的结构,因此我假设您具有以下饮料的数据库结构:

Screenshot of my Realtime database for this answer

{
  "Drinks" : {
    "-LYiUHm4vtrB3LqCBxEc" : {
      "location" : "toronto",
      "name" : "pepsi max",
      "price" : 13.5,
      "rating" : 3.6
    },
    "-LYiUHm5Lgt3-LENTdBZ" : {
      "location" : "new york",
      "name" : "diet coke",
      "price" : 15.45,
      "rating" : 5
    },
    "-LYiUHm5Lgt3-LENTdB_" : {
      "location" : "chicago",
      "name" : "mountain dew",
      "price" : 2,
      "rating" : 2
    },
    "-LYiUHm5Lgt3-LENTdBa" : {
      "location" : "vancouver",
      "name" : "sprite",
      "price" : 6.98,
      "rating" : 4.5
    }
  }
}

2。 Swift 4.0

现在,要使用名称搜索任何饮料,请使用以下代码:

func search(drinkName: String) {
        let databaseRef = Database.database().reference().child("Drinks")
        let query = databaseRef.queryOrdered(byChild: "name").queryStarting(atValue: drinkName).queryEnding(atValue: "\(drinkName)\\uf8ff")

        query.observeSingleEvent(of: .value) { (snapshot) in
            guard snapshot.exists() != false else { return }
            //print(snapshot.value)
            DispatchQueue.main.async {
                // Update TextFields here
            }
        }
}
  

以上查询中使用的\ uf8ff字符在Unicode范围内是一个很高的代码点。因为查询是在Unicode中大多数常规字符之后,所以该查询匹配所有以b开头的值。

来源:https://firebase.google.com/docs/database/rest/retrieve-data

  

注意:queryOrderedByChild()区分大小写。最好将所有字段都小写保存在数据库中,因为这样可以更轻松地查询数据。您始终可以在前端格式化字符串。

3。将“ .indexOn”添加到实时数据库的规则

为了使上面的查询起作用并获得更好的性能,您需要在要搜索的字段上设置索引。 您可以通过转到“规则”标签并添加如下所示的索引来完成此操作:

{
  "rules": {
    ".read": true,
    ".write": true,
      "Drinks": {
        ".indexOn": "name"
      }
  }
}

来源:More information on indexing data

更新后的问题的答案:

func searchT() {
        // You must cast pub variable as String.
        guard let pub: String = pubName.text else { return }

        print(pub)


        let databaseRef = Database.database().reference().child("Drinks")

        let query = databaseRef.queryOrdered(byChild: "pub").queryStarting(atValue: pub).queryEnding(atValue: "\(String(describing: pub))\\uf8ff")

        query.observeSingleEvent(of: .value) { (snapshot) in
            guard snapshot.exists() != false else {
                print("failing here")
                return }
            print(snapshot.value as Any)
            DispatchQueue.main.async {

                guard let dict = snapshot.value as? [String:Any] else {
                    print(snapshot)
                    return
                }

                let pubName = dict["pub"] as? String
                let pubLocation = dict["location"] as? String
                let price = dict["price"] as? String
                let rating = dict["rating"] as? String
                let comment = dict["comment"] as? String
            }
        }
    }