Swift - 如何将“shouldChangeTextInRange"与 Firebase 结合使用进行实时搜索? [英] Swift - How Can I use 'shouldChangeTextInRange' with Firebase for real time searching?
问题描述
我想知道如何使用 shouldChangeTextInRange 创建 Firebase 匹配Regex 查询 和列出当前结果.
我之前在 Parse 中做过,用于在 Parse Cloud 中搜索用户名或用户全名.如果有人为我指明在 Firebase 中实现它的道路,那就太好了.
//搜索更新func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) ->布尔{//根据用户名查找让 usernameQuery = PFQuery(className: "_User")usernameQuery.whereKey("username",matchesRegex: "(?i)" + searchBar.text!)usernameQuery.findObjectsInBackgroundWithBlock { (objects:[PFObject]?, error:NSError?) ->作废如果错误 == 零 {//如果根据用户名列中输入的文本没有找到对象,则按全名查找如果对象!.isEmpty {让 fullnameQuery = PFUser.query()fullnameQuery?.whereKey("fullname",matchesRegex:"(?i)" + self.searchBar.text!)fullnameQuery?.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in如果错误 == 零 {//清理self.usernameArray.removeAll(keepCapacity: false)self.avaArray.removeAll(keepCapacity: false)//找到相关对象对于对象中的对象!{self.usernameArray.append(object.objectForKey("username") as!String)self.avaArray.append(object.objectForKey("avatar") as!PFFile)}//重新加载self.tableView.reloadData()}})}}//清理self.usernameArray.removeAll(keepCapacity: false)self.avaArray.removeAll(keepCapacity: false)//找到相关对象对于对象中的对象!{self.usernameArray.append(object.objectForKey("username") as!String)self.avaArray.append(object.objectForKey("avatar") as!PFFile)}//重新加载self.tableView.reloadData()}返回真}
<块引用>
更新 1:
我无法使用相同的父名称来执行此操作,snap.value 没有给我响应,甚至无法编译.所以我尝试做两个单独的父节点:firebase 屏幕截图链接>
我在 xcode 控制台上收到 indexOn 安全警告 对于每个字母笔划 first_name 子节点:
<块引用>[Firebase] 使用未指定的索引.考虑将/people_spell 的 ".indexOn": "first_name/T" 添加到您的安全规则中以获得更好的性能
[Firebase] 使用未指定的索引.考虑将/people_spell 的 ".indexOn": "first_name/Te" 添加到您的安全规则中以获得更好的性能
...更多次
我已经尝试过这些安全规则,但没有解决这些问题.它不包含每个子节点.我该如何提供?
"people_spell": {".read": "auth !== null",".write": "auth !== null",".indexOn": "first_name"},人们": {".read": "auth !== null",".write": "auth !== null",".indexOn": "first_name"}
我正在使用这些代码行:
let peopleSpellRef = Firebase(url: "https://sampleproject.firebaseio.com/people_spell")让 peopleRef = Firebase(url: "https://sampleproject.firebaseio.com/people")func searchBar(searchBar: UISearchBar, shouldChangeTextInRange range: NSRange, replacementText text: String) ->布尔{self.usernameArray.removeAll(keepCapacity: false)peopleSpellRef.queryOrderedByChild("first_name/(searchBar.text!)").queryEqualToValue(true).observeEventType(.Value, withBlock: { 快照输入让枚举数 = snapshot.children而 let rest = enumerator.nextObject() as?FDataSnapshot {peopleRef.childByAppendingPath("(rest.key)").observeEventType(.Value, withBlock: { snapshot inself.usernameArray.removeAll(keepCapacity: false)让 str: String = (snapshot.value.objectForKey("first_name")) as!(细绳)打印(字符串)self.usernameArray.append(str)self.userkeyArray.append(snapshot.key)self.tableView.reloadData()})}self.usernameArray.removeAll(keepCapacity: false)self.tableView.reloadData()})返回真}
这不是 Firebase 的工作方式,您不能直接在 Firebase 中对子字符串进行实时搜索".但是,您可以格式化要搜索的 Firebase 数据,还有其他几种方法也可以实现目标.
一个很简单:将您的数据从 Firebase 加载到一个数组中,然后通过该数组进行 NSPredicate 搜索(或其他方法).
另一个是查询完整字符串很容易;只要将文本分解为您要搜索的块:
人人_0名字:泰德"姓氏:史崔克"位置:坐下面向前方"人_1名字:泰迪"
您可以在 first_name 中搜索Ted"或在 last_name 中搜索Stryker",但不能在 position 中搜索front".
现在解决方法并记住磁盘空间很便宜.
可以创建一个节点,让您以多种方式搜索内容
人人_0first_name//名字是上面的TedT:真的特:真的泰德:真的ed:真的d: 真的e: 真的人_1first_name//名字是上面的泰迪T:真的特:真的泰德:真的等等
通过这个结构,我们可以找到所有以 Ted 开头的名字
peopleRef.queryOrderedByChild("first_name/Ted").queryEqualToValue(true).observeEventType(.Value, withBlock: { 快照输入对于快照中的孩子.孩子{打印(子值)}})
可以进行其他搜索;搜索所有包含 e 或 Te 等的名字.
如果这纯粹是您正在搜索以在文本字段中执行自动填充的情况(例如),逐个按键地对 firebase 进行 ping 操作是行不通的.
将数据从 Firebase 加载到数组或字典(或其他)中可能是您最好的解决方案.
I wonder that how creating Firebase matchesRegex query and listing current results using shouldChangeTextInRange.
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.
// 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
I'm getting indexOn security warning for each letter stroke first_name subnodes on xcode console:
[Firebase] Using an unspecified index. Consider adding ".indexOn": "first_name/T" at /people_spell to your security rules for better performance
[Firebase] Using an unspecified index. Consider adding ".indexOn": "first_name/Te" at /people_spell to your security rules for better performance
... 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
}
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.
One is straightforward: load your data from Firebase into an array and NSPredicate search (or other methods) through the array.
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.
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
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.
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.
这篇关于Swift - 如何将“shouldChangeTextInRange"与 Firebase 结合使用进行实时搜索?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!