Searching Through Child Values Firebase/Swift

Searching through child values Firebase / Swift

When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.

let query = REF_USERS.queryOrdered(byChild: "displayname").queryEqual(toValue: input)
query.observeSingleEvent(of: .value) { (snapshot: FIRDataSnapshot) in {
for child in snapshot.children {
print(child.key)
}
}

Also see:

  • Firebase snapshot.key not returning actual key?
  • Firebase access keys in queryOrderBy
  • Firebase access keys in queryOrderBy
  • Firebase getting data in order

How to compare a certain value against Firebase child values?

I may be misunderstanding the question but it appears that you want to create a user if a given token does not already exist in Firebase.

A simple query would allow that;

let usersRef = self.ref.child("users")
let tokenToCompare = "duhfkNCIKW8APA9..." //abbreviated
let query = usersRef.queryOrdered(byChild: "fcmToken").queryEqual(toValue: tokenToCompare)
query.observe(.value, with: { snapshot in
if snapshot.exists() {
print("token exists, do not create user")
return
} else {
print("no existing token found, create user")
}
})

If the token exists, it will print that message and not continue. If the token does not exist, you can then insert the code to create the user.

...and if you want to get all denormalized, then add a separate node to keep track of the existing tokens

existing_tokens
jasoijaisas9: true
99i9kmkdodkf: true
duhfkNCIKW8APA9: true

then you can avoid the heavier query with a simple observe which is much lighter weight.

let existingTokensRef = self.ref.child("existing_tokens")
let tokenToFindRef = existingTokensRef.child("duhfkNCIKW8APA9")
tokenToFindRef.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() {
print("ok to create user")
} else {
print("token exists! Dont create user")
}
})

The only thing to watch with this technique is not having special characters in the keys.

Swift: Search for a specific value in Firebase Database & find all associated data

1. Realtime Database

Since you haven't included the structure of your database, I assume you have a database structure for drinks like below:

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

Now, to search any drink by name use below code:

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
}
}
}

The \uf8ff character used in the query above is a very high code point in the Unicode range. Because it is after most regular characters in Unicode, the query matches all values that start with a b.

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

Note: queryOrderedByChild() is case-sensitive. It is nice practice to save all fields lowercased in database as this makes it easier to query data. You can always format strings in front end.

3. Add ".indexOn" to Realtime Database's Rules

In order to above query to work and achieve better performance, you need to set the index on the field that you are going to search by.
You can do this by going to Rules tab and adding index like below:

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

Source: More information on indexing data

Updated Answer for your updated question:

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
}
}
}

Reading child value from firebase database in swift

You need ( observe / observeSingleEvent is up to you according to the logic of your app )

REF_FEEDMESSAGES.child("\(key)/likes").observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value

}) { (error) in
print(error.localizedDescription)
}

Using this .value(forKey: "likes") as! String for sure will crash the app , as it's not a local dictionary to query it's data synchronously

Swift Firebase read children of a child

Try the following and let me know if it works now:

// SEARCHES FOR SHARING CODE IN DATABASE (ONLINE)
let parentRef = Database.database().reference().child("Recipes")

parentRef.observeSingleEvent(of: .value, with: { snapshot in

// SHOWING WHATEVER WAS RECEIVED FROM THE SERVER JUST AS A CONFIRMATION. FEEL FREE TO DELETE THIS LINE.
print(snapshot)

// PROCESSES VALUES RECEIVED FROM SERVER
if ( snapshot.value is NSNull ) {

// DATA WAS NOT FOUND
print("– – – Data was not found – – –")

} else {

// DATA WAS FOUND
for user_child in (snapshot.children) {

let user_snap = user_child as! DataSnapshot
let dict = user_snap.value as! [String: String?]

// DEFINE VARIABLES FOR LABELS
let recipeName = dict["Name"] as? String
let recipeDescription = dict["Description"] as? String
print("– – – Data for the recipe \(recipeName) with the description \(recipeDescription) was found successfully! – – –")
}
}
}

If you only want to retrieve the name and description for one specific recipe, you should change the third line to

parentRef.queryEqual(toValue:DefineWhatToSearchForHere).observeSingleEvent(of: .value, with: { snapshot in

If you constantly want to update to reflect changes, you can either call this function every x seconds using a timer and adding it to override func viewDidLoad() such as

time = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ViewController.updateFBData), userInfo: nil, repeats: true)

after creating a function called func updateFBData() in which you do whatever you want to do to get new data (see above) and calling it in a defined timeInterval

or you can do what Attila Hegedüs in this excellent tutorial.

Get Children of Children in Firebase Using Swift

You can try

@IBAction func editAddressButtonPressed(_ sender: Any) {
self.ref?.child("Users").queryOrdered(byChild: "username").queryEqual(toValue: username.text!).observe(.value, with: { (snapShot) in
if !snapShot.exists() {
print("nothing found")
} else {
print("found it!")
print(snapShot)
let snapShotValue = snapShot.value as! [String:[String:Any]]
Array(snapShotValue.values).forEach {
let fName = $0["FirstName"] as! String
print(fName)
}

}
})
}


Related Topics



Leave a reply



Submit