Read data from firebase swift
You are listening for the .value
event, but your block is dealing with a single item at a time so use .childAdded
event for that.
let ref = FIRDatabase.database().reference().child("users").child("user").child(username)
ref.observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let userDict = snapshot.value as? [String:Any] {
//Do not cast print it directly may be score is Int not string
print(userDict["score"])
}
})
Note: In Swift use native Dictionary
instead of NSDictionary
Swift: how to retrieve data from firebase?
To read data from Firebase you attach a listener to a path which is what creates a FIRDatabase reference. A FIRDatabaseReference represents a particular location in your Firebase Database where there is a key-value pair list of children. So in your case, you have created a Firebase reference to the key "wins" which only points to a value and not a key-value pair. Your reference was valid up to this point:
ref = Database.database().reference().child(passUserID)
//did you mean FIRDatabase and not Database??
This FIRDatabaseReference points to the key passUserID which has a key-value pair list of children ["wins":"7"] and ["losses":"8"] (NOTE: a key is always a string). So from your FIRDatabase reference, you create your observer as follows and read the value of "wins":
ref?.observe(.childAdded, with: { (snapshot) in
//Convert the info of the data into a string variable
if let getData = snapshot.value as? [String:Any] {
print(getData)
let wins = getData["wins"] as? String
print("\(wins)")
}
})
The Child added event will fire off once per existing piece of data, the snapshot value will be an individual record rather than the entire list like you would get with the value event. As more items come in, this event will fire off with each item. So if "losses" is the first record you might not get the value of "wins". Is this what you are trying to achieve? If what you really wanted to know is the value of "wins" at that particular location and to know if this value has ever changed you should use the .value observer as follows:
ref?.observe(.value, with: { (snapshot) in
//Convert the info of the data into a string variable
if let getData = snapshot.value as? [String:Any] {
let wins = getData["wins"] as? String
print("\(wins)") //check the value of wins is correct
}
})
Or if you just wanted to get the know the value of wins just once and you are not worried about knowing if there any changes to it, use the "observeSingleEvent" instead of "observe".
EDIT
I saw your image and now realize you might also have a problem with your reference. Your ref should actually be something like:
ref = FIRDatabase.database().reference().child("game-").child(passUserID)
You have obscured what "game" is but a valid reference to "wins" will include it.
SECOND EDIT
I will add the following so you can properly debug the problem. Use this pattern to observe the value and see if you get an error returned and what is says:
ref.observe(.value, with: { (snapshot) in
print(snapshot)
}, withCancel: { (error) in
print(error.localizedDescription)
})
Normally it will give you an error if you cannot access that Firebase location because of a database rule. It will also be a good idea to see if print(snapshot) returns anything as above.
Retrieve firebase data from swift
Try something like that:
Database.database().reference()
.child("Stations").
observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else {
return
}
var stations = [Station]()
for (key, value) in values {
guard let station = value as? [String: Any],
let adresse = station["adresse"] as? String,
let codePostat = station["codePostat"] as? String else {
continue
}
stations.append(Station(adresse: adresse, codePostat: codePostat))
}
// if you have some completion return retrieved array of stations
completion(stations)
})
struct Station {
private let adresse: String
private let codePostat: String
init(adresse: String, codePostat: String) {
self.adresse = adresse
self.codePostat = codePostat
}
}
Get the data from all children in firebase using swift
You'll want to attach the observer one level higher in the JSON, and then loop over the child nodes:
ref.observeSingleEvent(of: .value) { snapshot in
for case let child as FIRDataSnapshot in snapshot.children {
guard let dict = child.value as? [String:Any] else {
print("Error")
return
}
let latitude = dict["Latitude"] as Any
let longtitude = dict["Longtitude"] as Any
print(longtitude)
print(latitude)
}
}
Loop syntax taken from Iterate over snapshot children in Firebase, but also see How do I loop all Firebase children at once in the same loop? and Looping in Firebase
How to read data from firebase
try this:-
ref = Database.database().reference()
ref.child("club").observe(.value, with: { (snapshot) in
print("clubs: \(snapshot)")
if(snapshot.exists()) {
let array:NSArray = snapshot.children.allObjects as NSArray
for obj in array {
let snapshot:FIRDataSnapshot = obj as! FIRDataSnapshot
if let childSnapshot = snapshot.value as? [String : AnyObject]
{
if let clubName = childSnapshot["name"] as? String {
print(clubName)
}
}
}
}
}
Swift Firebase get Data to Class Object
Well You need to change your datamodel first. You dont need to store id
value in , 12345
in this case. you can already fetch the key. Also, in /users/chats
, you just can just save the chat id as either chat1 : IBDrbfku887BLIY
or IBDrbfku887BLIY : true
. You can always fetch them through value or the key respectively.
And in your chat document, you just need to reference the user id, i.e just get them and store them as user1 and user2. You can add more users if your usecase requires more.
Reconfigure your Data Model as follows.
Now You need 2 Objects Users and Chats as follows :
Users.swift
class User : NSObject {
private var _name: String!
private var _username: String!
private var _userid: String!
private var _userRef: DatabaseReference!
var name: String! {
get {
return _name
} set {
_name = newValue
}
}
var username : String! {
get {
return _username
} set {
_username = newValue
}
}
var userid: String! {
get {
return _userid
} set {
_userid = newValue
}
}
var userRef: DatabaseReference! {
get {
return _userRef
} set {
_userRef = newValue
}
}
init(userid: String, userData: Dictionary<String, Any>){
self._userid = userid
_userRef = Database.database().reference().child(_userid)
if let username = userData["username"] as? String {
self._username = username
}
if let name = userData["name"] as? String {
self._name = name
}
}
}
Chats.swift
class Chat : NSObject {
private var _chatid: String!
private var _user1: String!
private var _user2: String!
private var _chatRef: DatabaseReference!
var user1: String! {
get {
return _user1
} set {
_user1 = newValue
}
}
var user2 : String! {
get {
return _user2
} set {
_user2 = newValue
}
}
var chatid: String! {
get {
return _chatid
} set {
_chatid = newValue
}
}
var chatRef: DatabaseReference! {
get {
return _chatRef
} set {
_chatRef = newValue
}
}
init(chatid: String, chatData: Dictionary<String, Any>){
self._chatid = chatid
_chatRef = Database.database().reference().child(_chatid)
if let user = chatData["users"] as? Dictionary<String, Any> {
if let user1 = user["user1"] as? String {
self._user1 = user1
}
if let user2 = user["user2"] as? String {
self._user2 = user2
}
}
}
}
The major issue/or an overlooked issue here is the type of the data. In the /users
, you id 12345
will be of type String
. But when you fetch the same from /chats
, it returns as Int
. This downloads the value but never converts it. Always take care while seeding/testing your data.
To fetch the user's credentials just reference that through another query. This is what you can do :
var allUsers = [User]()
var allChats = [Chat]()
func viewDidLoad() {
super.viewDidLoad()
fetchAllChats()
}
func getUser(from userId: String, completion: @escaping (User) -> Void) {
Database.database().reference().child("users").child(userId).observeSingleEvent(of: .value, with: { snapshot in
if let datasnap = snapshot.value as? Dictionary<String, Any> {
let user = User(userid: userId, userData: datasnap)
completion(user)
}
})
}
func fetchAllChats() {
Database.database().reference().child("chats").observeSingleEvent(of: .value, with: { snapshot in
allChat.removeAll()
if let snapshot = snapshot.value as? Dictionary<String, Any> {
for snap in snapshot {
if let chatd = snap.value as? Dictionary<String, Any> {
let chat = Chat(chatid: snap.key, chatData: chatd)
self.allChats.append(chat)
}
}
}
// collectionview.reloadData() <--------- only if required.
})
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let chatData = allChats[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellId, for: indexPath) as! Cell
getUser(from: chatData.user1) { user in
cell.label.text = user.usernme
}
return cell
}
Swift retrieve data from Firebase
You are observing the childAdded
event.
So your closure will only be executed when a new value I inserted into Users/Advertisements
.
Try this code instead
Database
.database()
.reference()
.child("Users")
.child(Auth.auth().currentUser!.uid)
.child("Advertisements")
.queryOrderedByKey()
.observeSingleEvent(of: .value, with: { snapshot in
guard let dict = snapshot.value as? [String:Any] else {
print("Error")
return
}
let imageAd = dict["imageAd"] as? String
let priceAd = dict["priceAd"] as? String
})
The closure will be executed only once and "almost" immediately.
How to read data from Firebase realtime database using loop
There's a bunch of ways to get to that data; I'll show two, a coding solution and then an alternative structure solution
Coding solution:
The ID's are unknown but the path to the parent node of those ID's is. So create a reference to the most-known key (the parent, 11) and then read the child nodes underneath.
Assemble them into an array of DataSnapshots (to keep the order) and then iterate over that array, getting the child data at numberOfTargets.
func readNumberOfTargets() {
let mayRef = self.ref.child("2020").child("May") //self.ref points to my firebase
let dayRef = mayRef.child("11")
dayRef.observeSingleEvent(of: .value, with: { snapshot in
let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
for child in childSnaps {
let mainSnap = child.childSnapshot(forPath: "main")
let numTargets = mainSnap.childSnapshot(forPath: "numberOfTargets")
print(child.key, numTargets)
}
})
}
and the output
Jan Snap (numberOfTargets) 80
borys Snap (numberOfTargets) 77
ftfvdf Snap (numberOfTargets) 99
Note that it looks like the numberOfTargets is being stored as a string so use this if that's the case
let numTargets = mainSnap.childSnapshot(forPath: "numberOfTargets").value as? String ?? "No Targets"
if it's being stored as an Int, use this
let numTargets = mainSnap.childSnapshot(forPath: "numberOfTargets").value as? Int ?? 0
Alternative Structure Solution:
It's common practice to denormalize your data in NoSQL databases and also using compound keys to get to it. In this case, we'll do both and create a seperate node that contains a highly flattened structure that's super easy to get to
TargetCount
2020_May_11_Jan: 80
2020_May_11_borys: 77
2020_May_11_ftfvdf: 99
So when you want the target count for each node, it can just be read based on the path. In other words, when this node is created
2020
May
11
Jan
they key 'Jan' (the unknown key per your question) is returned when that node is created. So at the same time write that path to the TargetCount node
TargetCount
2020_May_11_Jan: 80
As you iterate over the child nodes, you'll know the unknown by descontstucting the key string
2020_May_11 and then the Jan value is 80
You could also do this if you want to isolate the specific dates
TargetCount
2020_May_11
Jan:80
borys: 77
ftfvdf: 99
How to configure Firebase for Swift and read data out
The problem is that you are trying to access Firestore with Firebase methods.
"But then I try to access my data and it gives me nothing!" It gives you nothing because there is no data in Firebase, all your data is in Firestore.
See this guide for Firestore: https://firebase.google.com/docs/firestore/quickstart
and this one to understand the differences between Firebase and Firestore:
https://firebase.google.com/docs/database/rtdb-vs-firestore
Related Topics
Why Are Iboutlets Optionals After Swift 5 Migration
How to Set Title of Navigation Bar in Swift
Case Insensitive Dictionary in Swift
In Swift, When Using "[Weak Self] In", Should I Double Up on It When Nested Inside Another Closure
Select Next Nstextfield with Tab Key in Swift
Swift Subtle Difference Between Curried and Higher Order Function
Swift, Nsjsonserialization and Nserror
Swift 2.0 Constraintswithvisualformat
Realitykit - Set Text Programmatically of an Entity of Reality Composer
Swift Delegate for a Generic Class
Swift Diffabledatasource Make Insert&Delete Instead of Reload
How to Rounded the Corners When I Draw Rectangle Using Uibezierpath Points
Module File's Deployment Target Is iOS9.0 V9.0 with Xcode 7/Swift 2
Change Default Global Tint Color in Swift
How to Get Motion Events with the Apple Tv Remote
Difference Between String Interpolation and String Concatenation