I\'m writing code that is appending elements from firebase to an array to perform a simple search using a textfield.
The code for the method is below:
It appears the question is
"How can I query for a value contained in a child node?"
Given a structure similar to the original
"events" : {
"CCDS" : {
"attend:count" : 1,
"event:imageURL" :"someURL",
"event:name" : "Center City District Sips"
"MIA" : {
"attend:count" : 1,
"event:imageURL" : "someURL",
"event:name" : "Made In America"
a Firebase query would return the node you want.
If the user typed in Made In America and tapped the search button here's the query to return that node in a snapshot.
let searchString = "Made In America"
let ref = self.ref.child("events")
let query = ref.queryOrdered(byChild: "event:name").queryEqualTo(searchString)
query.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let eventDict = snap.value as! [String: Any]
let attendCount = eventDict["attend:count"] as! String
let url = eventDict["event:imageURL"} as! String
}
})
If you want to do a partial string match, where the user could type in just a few characters like Made the code is similar but you need to let firebase return all of the matches starting with Made...
The query would look like this
let startString = "Made"
let endString = "Made" + "\\uf8ff"
let query = ref.queryOrdered(byChild: "event:name")
.queryStarting(atValue: startString)
.queryEnding(atValue: endString")
The "\uf8ff" is a character at a very high code level in Unicode - because of that it encompasses all of the preceeding characters.
However, querying 'on the fly' can create an unresponsive or sluggish UI so it's not recommended.
An alternative is to create a seperate node that contains a lot less info and contains the elements the user would search for and a reference to the event node.
So the main node containing all the data looks like this
"events" : {
"-uyuh8s8j8jsdas" : {
"event": "CCDS"
"attend:count" : 1,
"event:imageURL" : "someURL",
"-y88jsijsijjids" : {
"event": "MIA"
"attend:count" : 1,
"event:imageURL" : "someURL",
and a 'smaller' node would look like this
events_for_searching
-uyuh8s8j8jsdas
event:name: "Center City District Sips"
-y88jsijsijjids
event:name: "Made In America"
With this, you could load all of the nodes from the events_for_searching into an array (then filter the array as the user types) which would make the UI very responsive and when the user selects a name, you can then use the key from that node as a reference to load the data from the events node via an observeSingleEvent function.
EDIT
In response to a comment, I wanted to add a bit more detail in code.
Here's my structure
"events" : {
"event_0" : {
"event:name" : "An Event"
},
"event_1" : {
"event:name" : "Made In America"
}
},
and the code to query for event:name: Made In America
let searchString = "Made In America"
let ref = self.ref.child("events")
let query = ref.queryOrdered(byChild: "event:name").queryEqual(toValue: searchString)
query.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String: Any] else{
print(snapshot.value)
return
}
print(snapshot.value)
}) { (err) in
print("Failed to fetch event data", err)
}
and the output
Optional({
"event_1" = {
"event:name" = "Made In America";
};
})