Swift - 如何在Firebase中使用'shouldChangeTextInRange'进行实时搜索?

时间:2023-01-25 09:56:26

I wonder that how creating Firebase matchesRegex query and listing current results using shouldChangeTextInRange.

我想知道如何使用shouldChangeTextInRange创建Firebase matchesRegex查询和列出当前结果。

I have did it before in Parse for searching username or user fullname in Parse Cloud. If someone shed light my path to do it in Firebase, it would be great.

我之前在Parse中已经在Parse Cloud中搜索用户名或用户fullname。如果有人在Fi​​rebase中轻松实现这一目标,那就太棒了。

// search updated
func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    // find by username
    let usernameQuery = PFQuery(className: "_User")
    usernameQuery.whereKey("username", matchesRegex: "(?i)" + searchBar.text!)
    usernameQuery.findObjectsInBackgroundWithBlock { (objects:[PFObject]?, error:NSError?) -> Void in

        if error == nil {

            // if no objects are found according to entered text in username column, find by fullname
            if objects!.isEmpty {

                let fullnameQuery = PFUser.query()
                fullnameQuery?.whereKey("fullname", matchesRegex: "(?i)" + self.searchBar.text!)
                fullnameQuery?.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in

                    if error == nil {

                        // clean up
                        self.usernameArray.removeAll(keepCapacity: false)
                        self.avaArray.removeAll(keepCapacity: false)

                        // found related objects
                        for object in objects! {
                            self.usernameArray.append(object.objectForKey("username") as! String)
                            self.avaArray.append(object.objectForKey("avatar") as! PFFile)
                        }

                        // reload
                        self.tableView.reloadData()

                    }

                })

            }

        }

        // clean up
        self.usernameArray.removeAll(keepCapacity: false)
        self.avaArray.removeAll(keepCapacity: false)

        // found related objects
        for object in objects! {
            self.usernameArray.append(object.objectForKey("username") as! String)
            self.avaArray.append(object.objectForKey("avatar") as! PFFile)
        }

        // reload
        self.tableView.reloadData()

    }

    return true

}

Update 1:

I couldn't do it using same parent name, snap.value didn't give me response, even not compile. So I have tried to do two separate parent node like that: firebase screen shot link

我无法使用相同的父名称,snap.value没有给我回复,甚至没有编译。所以我试图做两个单独的父节点:firebase屏幕截图链接

I'm getting indexOn security warning for each letter stroke first_name subnodes on xcode console:

我在xcode控制台上为每个字母描边f​​irst_name子节点获取indexOn安全警告:

[Firebase] Using an unspecified index. Consider adding ".indexOn": "first_name/T" at /people_spell to your security rules for better performance

[Firebase]使用未指定的索引。考虑在/ people_spell中将“.indexOn”:“first_name / T”添加到您的安全规则中,以获得更好的性能

[Firebase] Using an unspecified index. Consider adding ".indexOn": "first_name/Te" at /people_spell to your security rules for better performance

[Firebase]使用未指定的索引。考虑在/ people_spell中将“.indexOn”:“first_name / Te”添加到您的安全规则中,以获得更好的性能

... much more times

......更多次

I have tried these security rules it didn't solve these problems. It doesn't encompass each subnodes. How Can I provide this?

我已经尝试过这些安全规则并没有解决这些问题。它不包含每个子节点。我怎么能提供这个?

"people_spell": {
      ".read": "auth !== null",
      ".write": "auth !== null",
      ".indexOn": "first_name"
    },
"people": {
      ".read": "auth !== null",
      ".write": "auth !== null",
      ".indexOn": "first_name"
}

I'm using these lines of codes:

我正在使用这些代码行:

let peopleSpellRef = Firebase(url: "https://sampleproject.firebaseio.com/people_spell")
let peopleRef = Firebase(url: "https://sampleproject.firebaseio.com/people")

func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

   self.usernameArray.removeAll(keepCapacity: false)

   peopleSpellRef.queryOrderedByChild("first_name/\(searchBar.text!)").queryEqualToValue(true)
    .observeEventType(.Value, withBlock: { snapshot in

        let enumerator = snapshot.children
        while let rest = enumerator.nextObject() as? FDataSnapshot {

            peopleRef.childByAppendingPath("\(rest.key)").observeEventType(.Value, withBlock: { snapshot in

                self.usernameArray.removeAll(keepCapacity: false)

                let str: String = (snapshot.value.objectForKey("first_name")) as! (String)
                print(str)
                self.usernameArray.append(str)
                self.userkeyArray.append(snapshot.key)

                self.tableView.reloadData()
            })
        }


        self.usernameArray.removeAll(keepCapacity: false)
        self.tableView.reloadData()

    })

return true
}

1 个解决方案

#1


2  

This is not how Firebase works and you can't directly do a 'real time search' in Firebase for a substring. But, you can format your Firebase data to be searched and there are a couple of other methods which will also accomplish the goal.

这不是Firebase的工作原理,您无法直接在Firebase中对子字符串进行“实时搜索”。但是,您可以格式化要搜索的Firebase数据,还有其他一些方法也可以实现目标。

One is straightforward: load your data from Firebase into an array and NSPredicate search (or other methods) through the array.

一个是直截了当的:将数据从Firebase加载到数组中,并通过数组进行NSPredicate搜索(或其他方法)。

Another is that query'ing for full strings is easy; as long as the text is broken up into the chunks you want to search for:

另一个是查询完整字符串很容易;只要文本被分解为您要搜索的块:

people
  person_0
    first_name: "Ted"
    last_name: "Stryker"
    position: "sitting down and facing front"
  person_1
    first_name: "Teddy"

You can search for 'Ted' in first_name or 'Stryker' in last_name but you cannot search for 'front' in position.

您可以在first_name中搜索“Ted”或在last_name中搜索“Stryker”,但不能在位置搜索“front”。

Now the workaround and keep in mind disk space is cheap.

现在解决方法并记住磁盘空间很便宜。

A node can be created that will let you search for stuff in a variety of ways

可以创建一个节点,让您以各种方式搜索内容

people
  person_0
   first_name //First name is Ted from above
    T: true
    Te: true
    Ted: true
    ed: true
    d: true
    e: true
  person_1
   first_name  //First name is Teddy from above
    T: true
    Te: true
    Ted: true
    etc

With this structure we can find all first names that start with Ted

通过这种结构,我们可以找到以Ted开头的所有名字

    peopleRef.queryOrderedByChild("first_name/Ted").queryEqualToValue(true)
         .observeEventType(.Value, withBlock: { snapshot in

        for child in snapshot.children {
          print(child.value)  
        }
    })

Other searches can be performed; searching for all first names that contain e or Te etc.

可以执行其他搜索;搜索包含e或Te等的所有名字。

If this is purely a situation where you are searching to perform an autofill in a text field (for example) pinging firebase on a keystroke by keystroke basis isn't going to work well.

如果这纯粹是你正在搜索在文本字段中执行自动填充的情况(例如),按键击键击击击火基不能很好地工作。

Loading the data from Firebase into an array, or dictionary (or whatever) will probably be your best solution.

将Firebase中的数据加载到数组或字典(或其他)中可能是您​​的最佳解决方案。

#1


2  

This is not how Firebase works and you can't directly do a 'real time search' in Firebase for a substring. But, you can format your Firebase data to be searched and there are a couple of other methods which will also accomplish the goal.

这不是Firebase的工作原理,您无法直接在Firebase中对子字符串进行“实时搜索”。但是,您可以格式化要搜索的Firebase数据,还有其他一些方法也可以实现目标。

One is straightforward: load your data from Firebase into an array and NSPredicate search (or other methods) through the array.

一个是直截了当的:将数据从Firebase加载到数组中,并通过数组进行NSPredicate搜索(或其他方法)。

Another is that query'ing for full strings is easy; as long as the text is broken up into the chunks you want to search for:

另一个是查询完整字符串很容易;只要文本被分解为您要搜索的块:

people
  person_0
    first_name: "Ted"
    last_name: "Stryker"
    position: "sitting down and facing front"
  person_1
    first_name: "Teddy"

You can search for 'Ted' in first_name or 'Stryker' in last_name but you cannot search for 'front' in position.

您可以在first_name中搜索“Ted”或在last_name中搜索“Stryker”,但不能在位置搜索“front”。

Now the workaround and keep in mind disk space is cheap.

现在解决方法并记住磁盘空间很便宜。

A node can be created that will let you search for stuff in a variety of ways

可以创建一个节点,让您以各种方式搜索内容

people
  person_0
   first_name //First name is Ted from above
    T: true
    Te: true
    Ted: true
    ed: true
    d: true
    e: true
  person_1
   first_name  //First name is Teddy from above
    T: true
    Te: true
    Ted: true
    etc

With this structure we can find all first names that start with Ted

通过这种结构,我们可以找到以Ted开头的所有名字

    peopleRef.queryOrderedByChild("first_name/Ted").queryEqualToValue(true)
         .observeEventType(.Value, withBlock: { snapshot in

        for child in snapshot.children {
          print(child.value)  
        }
    })

Other searches can be performed; searching for all first names that contain e or Te etc.

可以执行其他搜索;搜索包含e或Te等的所有名字。

If this is purely a situation where you are searching to perform an autofill in a text field (for example) pinging firebase on a keystroke by keystroke basis isn't going to work well.

如果这纯粹是你正在搜索在文本字段中执行自动填充的情况(例如),按键击键击击击火基不能很好地工作。

Loading the data from Firebase into an array, or dictionary (or whatever) will probably be your best solution.

将Firebase中的数据加载到数组或字典(或其他)中可能是您​​的最佳解决方案。