Fetch first key from firebase database with swift 4 using ChildAdded - ios

I'm trying to fetch the first key from my firebase database but for some reason nothing is being printed out. How can I get the first key from my firebase database using .childAdded
let userMessagesRef = Database.database().reference().child("user-message").child(uid).child(userId)
userMessagesRef.observe(.childAdded, with: { (snapshot) in
guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
print(first)

This in incredibly easy if you literally are asking how to only ever get the first child of a node. Here's how to only get the first child of a /users node
func getFirstChild() {
let usersRef = self.ref.child("users")
usersRef.observeSingleEvent(of: .childAdded, with: { snapshot in
print(snapshot)
})
}
or
print(snapshot.key)
if you just want the key.
Or, if you want to use a query to do the same thing
func getFirstChildAgain() {
let usersRef = self.ref.child("users")
let query = usersRef.queryOrderedByKey().queryLimited(toFirst: 1)
query.observeSingleEvent(of: .value, with: { snapshot in
print(snapshot)
})
}

The child_added event is typically used when retrieving a list of items from the database. Unlike value which returns the entire contents of the location, child_added is triggered once for each existing child and then again every time a new child is added to the specified path. The event callback is passed a snapshot containing the new child's data. For ordering purposes, it is also passed a second argument containing the key of the previous child.
From: Read and Write Data on iOS
Per your requirements, this is possible in .value and childAdded.
var child_array = [String:String]
let userMessagesRef = Database.database().reference().child("user-message").child(uid).child(userId)
userMessagesRef.observe(.childAdded, with: { (snapshot) in
let value = snapshot.value as? String ?? "Empty String"
let key = snapshot.key
child_array[key] = value;
}) { (error) in
print(error.localizedDescription)
}
then:
if let first = child_array.first?.key {
print(first) // First Key
}
Big NOTE: child_added randomly collects this data, you should never use it to sort your data

Related

How to get value of nested branch in firebase swift

I'm new to setting up firebase's realtime database, and I'm trying to access the content from a message to display in the app.
Here is how my database is structured:
I want to access "content" for each of the messages with the fewest value for "numberofresponses."
let ref: DatabaseReference! = Database.database().reference(withPath: "messagepool")
ref.queryOrdered(byChild: "numberofresponses").observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() {
print("no snapshot exists")
return }
print(snapshot)
The above code correctly prints the "messagepool," but I want the specific content value from each of the branches. I seem to be missing something. What is the correct way to do this? Thanks
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.
So in your closure/completion handler you will need to loop over snapshot.children to get at the individual result snapshot(s):
ref.queryOrdered(byChild: "numberofresponses").observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() {
print("no snapshot exists")
return
}
for childSnapshot in querySnapShot.children.allObjects as! [DataSnapshot] {
print(childSnapshot.key)
print(childSnapshot.value)
guard let value = childSnapshot.value as? [String: Any] else { return }
do {
guard let content = value["content"] as? String,
...
}
}
}
Also see:
Firebase queryOrderedByChild() method not giving sorted data
Retrieving Data using Firebase Swift
Getting nil in parsing Firebase values swift using Codable and CodableFirebase

Print All Children Columns from Firebase - iOS Swift 4

I have 2 records in my users table
This code below
let fcmTokenRef = Database.database().reference().root.child("users").child(id!).child("fcmToken")
fcmTokenRef.observe(DataEventType.value, with: { (snapshot) in
print(">>",snapshot)
})
will print out the token of a child
How do I adjust my code to print all the tokens for all my children?
You can try
let fcmTokenRef = Database.database().reference().root.child("users").observe(DataEventType.value, with: { (snapshot) in
print(">>",snapshot)
let dic = snapshot.value as! [String:[String:Any]]
Array(dic.values).forEach {
let str = $0["fcmToken"] as! String
print(str)
}
})
You’re requesting a onetime read, hence you’re reading the data once. You need to use .childAdded
Try this:
let fcmTokenRef = Database.database().reference().child(“users”)
fcmTokenRef.observe(.childAdded, with: { (snapshot) in
print(">>",snapshot)
guard let data = snapshot as? NSDictionary else {return}
var each_token = data[“fcmToken”] as? String
print(“all tokens: \(each_token!)”)
})
#puf says something very important:
differences between child added and value firebase
The child_added event fires for each matching child under the node that you query. If there are no matching children, it will not fire.

Getting conditionals to work within Firebase Observer

I am trying to do a conditional within Firebase Observer.
Essentially I like to check if seat is occupied.
If it is, then orders can be retrieved.
If not then send the restaurant back to the search seat page again.
For some reason, the code within if !taken is never executed even if the condition is met (ie. the owner has inputted the wrong seat number). I have put it within the closure, it should run right?
func retrieveData (){
var taken = false
var seatNumber = "**an Int from other page**"
let refCustomer = Database.database().reference().child("Restaurant").child("Customers")
refCustomer.queryOrdered(byChild: "Seat").queryEqual(toValue: "\(seatNumber)").observeSingleEvent(of: .childAdded, with: { (snapshot) in
if snapshot.exists() {
taken = true
let snapshotValue = snapshot.value as? [String : AnyObject] ?? [:]
self.customerFirstName = snapshotValue["Firstname"] as! String
self.customerLastName = snapshotValue["Lastname"] as! String
self.customerAllergy = snapshotValue["Allergy"] as! String
self.customerID = snapshot.key
self.allergy.text = self.customerAllergy
self.ptname.text = "\(self.customerFirstName) \(self.customerLastName)"
}
if !taken {
print ("oops")
self.performSegue(withIdentifier: "MainPage", sender: self)
}
})
}
There are a number of issues with this code, and possibly your structure so let me see if I can point you in the right direction.
First, you can eliminate the taken varable as it's unneeded. In short
if snapshot.exists() {
//handle the snapshot
} else { //use else here as if the snapshot doesn't exist we want this code to run
print ("oops")
}
Second, ensure your structure is like this
Customers
cust_0
Seat: 1
cust_1
Seat: 2
etc
Third, this is a string of "1"
queryEqual(toValue: "\(seatNumber)")
and you want to query for an Int so make it
queryEqual(toValue: seatNumber)
which queries for an Int of 1
Forth:
When querying Firebase, closures will not execute when .childAdded doesn't find anything. You should use .value.
From the docs of .childAdded
This event is triggered once for each existing child and then again
every time a new child is added to the specified path.
So if no child nodes match the query, it will not execute.
Use this
refCustomer.queryOrdered(byChild: "Seat")
.queryEqual(toValue: seatNumber)
.observeSingleEvent(of: .value, with: { (snapshot) in
And... this is the important part, .value retrieves all nodes that match the query so you will need to iterate over those nodes to work with the child nodes. Assuming there would only ever be one match then you can do this
guard let allChildren = snapshot.children.allObjects as? [DataSnapshot] else {return}
let firstChild = allChildren.first
Fifth. While technically this is ok
let f = snapshotValue["Firstname"] as! String
You are guaranteeing that a Firstname node always exists. If that's true go with it. However, a safer, more Swifty way would be to do this
let f = snapshotValue["Firstname"] as? String ?? "No First Name"

Manipulating data after retrieved it from Firebase

Here's my code:
//Get data from Firebase
func getData(withBlock completion:#escaping() ->Void){
let ref = Database.database().reference().child("hobbies")
let query = ref.queryOrdered(byChild: "cost").queryEqual(toValue: "low")
query.observe(.childAdded, with: {(snapshot) in
self.user_choice_Cost.append((snapshot.childSnapshot(forPath: "hobbyName").value as? String)!)
completion()
//print(self.user_choice_Cost)
})
{ (error) in
print(error)
}
//Manipulating data
getData{
let set2:Set<String> = ["a"]
let set1:Set<String> = Set(self.user_choice_Cost)
print(set1.union(set2))}
This works correctly! But is there any way I can get the user_choice_Cost with all value(["a","b"]) instead of one by one(["a"],["a","b")] and manipulate user_choice_Cost array without putting it inside inside getData{}. Because if I put that outside it will return only "a"
When you observe .childAdded, your completion handler gets called for each individual child that matches your query. If you want to get called only once for all matching children, you should observe .value:
query.observe(.value, with: {(snapshot) in
Since your completion handler gets called only once, the snapshot in this case contains all matching nodes. So you need to loop over snapshot.children:
query.observe(.value, with: {(snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
let value: String = (child.childSnapshot(forPath: "hobbyName").value as? String)!;
user_choice_Cost.append(value)
}
print("value \(user_choice_Cost)")
})
With this code you'll only see one logging output, with all matching hobby names.

How to extract child of node in data snapshot

My firebase set up is as such:
Parent_node:{
Type:{
1476663471800:{ //This is a timestamp = Int64(date.timeIntervalSince1970 * 1000.0)
uid: USERS_UID;
}
}
}
how would I access the users uid? I have tried the following code, but its not extracting the UID
self.databaseRef.child("Parent_node/\(Type)").queryLimitedToLast(5).observeEventType(.Value, withBlock: { (snapshot) in
print(snapshot)
if let userDict = snapshot.value as? [String:AnyObject]{
for each in userDict{
let uidExtraced = each
print(uidExtraced)
//("1476663471700", [uid: USERS_UID])
First of all use snapshot.value?.allValues to get values and than parse it...
if snapshot.exists() {
for value in (snapshot.value?.allValues)!{
print(value) // you get [uid: USERS_UID] here
// ... parse it to get USERS_UID
print("user_id -- \(value["uid"])")
}
}
With this method, order of child might be different. For ordered nodes, you can use snapshot.child

Resources