When retrieving data from Firebase Database, <null> is returned: "Snap (...) <null>" - swift

I'm a relatively new Swift programmer and am using Firebase for the first time so please excuse any misunderstandings I may have and my lack of knowledge about terminology.
I am attempting to retrieve data about a user that is stored in a database (email and username).
The code successfully finds the userID in the database. The userID is then used in order to navigate into the directory containing the username and email. It stores those values in snapshot.
For some reason, when snapshot is printed, it shows the userID but the contents of the directory (username and password) are shown as <null>. I am certain that the directory I am attempting to access and retrieve data from exists and is not empty (it contains a username and email). I wantsnapshot to store the username and email, but printing shows that it is not doing so correctly and I cannot figure out why.
here is my code block:
func checkIfUserIsLoggedIn() {
if Auth.auth().currentUser?.uid == nil {
perform(#selector(handleLogout), with: nil, afterDelay: 0)
} else {
let uid = Auth.auth().currentUser?.uid;
Database.database().reference().child("Users").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let dictionary = snapshot.value as?[String:AnyObject] {
self.userLabel.text = dictionary["name"] as? String
}
}, withCancel: nil)
}
}
and here is what is being printed to the console:
Snap (ywU56lTAUhRpl3csQGI8W8WmQRf1) <null>
Here is the database entry I am attempting to reach and log to snapshot:
I'm a new Stack Overflow user and don't have enough experience on the site to be allowed to embed images in posts, so this is the external link
Thanks for reading, any help would be much appreciated!!

Your reference in Firebase is to "users", but you are using .child("Users") in your code. Make sure your lookup matches case to your node. I find it best to create a reference to that node and use it for writing to and reading from.
let usersRef = Database.Database().reference().child("users")
Snap (ywU56lTAUhRpl3csQGI8W8WmQRf1) <null> the portion in parenthesis refers to the end node of what you are trying to observe. In this case it refers to uid!.

if u want to get username or email then you make first the model class for
Example:-
class User: NSObject {
var name: String?
var email: String?
}
then user firebase methed observeSingleEvent
FIRDatabase.database().reference().child("user").child(uid).observeSingleEvent(of: .value, with: { (snapShot) in
if let dictionary = snapShot.value as? [String: Any]{
// self.navigationItem.title = dictionary["name"] as? String
let user = User()
user.setValuesForKeys(dictionary)
self.setUpNavigationBarWithUser(user: user)
}
})`

if it is not finding your asking values, you are asking wrong directory. check firebase db child name it must be exactly like in your code ("Users")

Related

How to check if a Firebase DB node value is true using swift?

I have the following Firebase DB structure (see pic) which is created when a user sends a compliment to another user.
The compliment is saved under compliments with an auto-generated id
The compliment.key is also saved under users-compliments, under senderID/receiverID/then the "complimentID":"boolean" pair to indicate if it is "active"
I wish to check if an "active" compliment exists before being allowed to send another one to the same user.
But the following query results in a null output even though there is a child node with a value of 1.
What am I doing wrong here?
Query:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).queryEqual(toValue: "1").observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
}
Console output:
snap: Optional(<null>)
When using queryEqual() you have to combine it with an queryOrderedBy. In your case it would be queryOrderedByValue() because you want to compare the value:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).queryOrderedByValue().queryEqual(toValue: "1").observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
}
More information about this can be found in the docs.
Try this:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
if let _ = snapshot.value as? NSNull {
// do your thing
}
}

Get youngest child in Firebase users

I want to find the youngest user in my list of users and load their data: name, profile pict, and current job assignments. I have read the Firebase primer on querying data, but their examples don't work for me because my data is organized differently. I have an additional child layer.
This is my JSON tree in Firebase:
I've tried loading the list of users and then iterating over them to find the youngest user, but that seems like overkill. The Firebase documentation makes me think I should be able to do the query through a Firebase method, like 'queryOrderedByChild' or similar.
I've gone over the old documentation here and the new documentation here, but I'm still left wondering what to do.
So this is my workflow:
The app will find the youngest user in the list of "members" and load their name, profile pict, birthday, etc. They will choose from a list of jobs. Once that user has chosen from the lists of available jobs, the app will load the next youngest user from the list of "members", and so on until all users have been loaded and have been given the chance to select jobs.
I think a better workflow would be this:
Get youngest user by utilizing a Firebase query
Use that query to load that user (image and name)
How would I go about doing that?
EDIT #1: Code I've Tried
func loadExistingUsers(completion: #escaping ([[String : Any]]) -> ()) {
var dictionary = [[String : Any]]()
ref.child("members").observeSingleEvent(of: .value) { (snapshot: FIRDataSnapshot) in
for child in snapshot.children {
let snap = child as! FIRDataSnapshot
if let value = snap.value as? [String : Any] {
dictionary.append(value)
}
}
completion(dictionary)
}
}
And then in ViewDidLoad:
loadExistingUsers { (dictionary) in
var youngestBirthday = 19000101
var userName = "Sophie"
for item in dictionary {
let fetchedBirthday = item["birthday"] as! Int
let fetchedName = item["firstName"] as! String
if fetchedBirthday > youngestBirthday {
youngestBirthday = fetchedBirthday
userName = fetchedName
}
}
print(userName,youngestBirthday)
}
This method returns the youngest user from my list of users, but it seems like an awfully long way to go to get what I want. I have to first fetch the users from Firebase, and then parse the snapshot, then create an array, then sort the array, then get the user name. I was under the impression Firebase could do all that with one query. Am I wrong?
You can get the youngest child using this code: (since your youngest date is the largest number so I am using toLast)
ref.child("members").queryOrdered(byChild:"birthday").queryL‌​im‌​ited(toLast: 1).observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let value = snapshot.value as? [String: Any] {
let name = value["firstname"] as? String
//you can do for other values as well
print(name)
}
})

Firebase: How to get User.uid?

I'm using Firebaseauth to manage users and data for my iOS app. The users can log in, and their userinfo is stored correct in the database.
But when I try to get the users to write to the database in a different viewController, using this string:
self.ref.child("users").child(user.uid).setValue(["username": username])
The thrown error is
Type user has no member .uid
That makes sense I guess, since I haven't created the variable. But I can't figure out how to declare it?
This is how you get the user's uid:
let userID = Auth.auth().currentUser!.uid
UPDATE: Since this answer is getting upvotes, make sure you prevent your app from crashing by using guards:
guard let userID = Auth.auth().currentUser?.uid else { return }
You might want to use a guard, as a force unwrap might break your app if a user isn’t signed in.
guard let userID = Auth.auth().currentUser?.uid else { return }
FIRAuth has actually been renamed to Auth. So, as per the latest changes, it will be
let userID = Auth.auth().currentUser!.uid
Edit.
As pointed out in comments, A force unwrap may crash the app.
guard let userID = Auth.auth().currentUser?.uid else { return }

Value not being removed from dictionary

I have a dictionary in Firebase called peopleWhoLike, the key is an auto-id and the value is the uid of the user who liked, I'm trying to loop through the peopleWhoLike dictionary and find the entry with the current users uid as the value so that I can remove it, but the value is not being removed.
func removeLike(postID: String){
ref.child("posts").child(postID).observe(.value, with: { (snapshot) in
if let info = snapshot.value as? [String : AnyObject]{
if var peopleWhoLike = info["peopleWhoLike"] as? [String : String]{
print("peopleWhoLike - \(peopleWhoLike)")
for person in peopleWhoLike{
if person.value == FIRAuth.auth()!.currentUser!.uid{
peopleWhoLike.removeValue(forKey: person.key)
print("personkey - \(person.key)")
}
}
}
}
})
}
Both print statements print correctly, ie person.key being the correct key
Any help would be much appreciated thanks!
you have only an snapshot (a copy) of the data there
to remove the value from the firebase database;
try this:
//path should be like this (i guess):
let currentUserUid = FIRAuth.auth()!.c‌​urrentUser!.uid
ref.child("posts")
.child(postId)
.child("peopleWhoLike")
.chi‌​ld(currentUserUid)
.rem‌​oveValue()
or same:
let currentUserUid = FIRAuth.auth()!.c‌​urrentUser!.uid
ref.child("posts/\(postId)/peopleWhoLike/\(currentUserUid)").rem‌​oveValue()
UPDATE
you you like to remove the person key - then you can:
a) iterate over peopleWhoLike and find if it is the user ( but please put this let currentUserUid = FIRAuth.auth()!.c‌​urrentUser!.uid outside the loop!
//path should be like this (i guess):
let currentUserUid = FIRAuth.auth()!.c‌​urrentUser!.uid
// loop and when match `person.value == currentUserUid` then:
ref.child("posts")
.child(postId)
.child("peopleWhoLike")
.chi‌​ld(person.key) //<-- change here
.rem‌​oveValue()
b) you search in the query. and remove then the resulting node.
ref.child("posts")
.child(postId)
.child("peopleWhoLike")
.startAt(currentUserId)
.endAt(currentUserId)
. [...] do something
i dont know if you can direct call .removeValue() at this point. but with a SingleEvent and an snapshot you can do snapshot.ref.removeValue() - doublecheck before you delete. but since this results in a reference you should direct able to call .removeValue()
ref.child("posts")
.child(postId)
.child("peopleWhoLike")
.startAt(currentUserId)
.endAt(currentUserId)
.removeValue()
note: this search takes longer than a direct path
see here doc for query:
https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html#byemail
https://firebase.google.com/docs/database/ios/read-and-write#delete_data
NOTE:
i would advice you to save it with the userUid as key because you only need a onliner to delete (see my first codesnippet where you not need to get all data from peopleWhoLike) and as value just 1 or you can save the current date (then you know when it was liked)

Retrieve data from an unknown child name with Firebase and Swift

I'm using Firebase as the database for my IOS app. I want to retrieve data of several users from the database.
Here is my database organization:
Users
UserID1
Location: value1
UserID2
location: Value2
...
I want to retrieve the location data of all the users of the database.
The basic snapshot fonction
ref.child("Users").child("").child("Location").observe(.value, with: {
snapshot in
for Location in snapshot.children {
self.locationsArray.append((Location as AnyObject).key)
}
print(self.locationsArray)
})
My question is: how can I retrieve all the Locations even if I don't specify (I can't) the userID that is the name of a child before? Thanks.
Here's a code snippet that retrieves and prints the uid of each user and their location.
We can further refine our results with a .query
let usersRef = ref.child("users")
usersRef.observeSingleEvent(of: .value, with: { (snapshot) in
for snap in snapshot.children {
let userSnap = snap as! FIRDataSnapshot
let uid = userSnap.key //the uid of each user
let userDict = userSnap.value as! [String:AnyObject] //child data
let location = userDict["Location"] as! String
print("key = \(uid) is at location = \(location)")
}
})
It is not possible with Firebase to retrieve just the Location.
There are a lot of option, but I see two that fits better in your case:
Get everything from all users, and then manage in your code what you want;
Create another dictionary only with users id and location.
The second option would be like:
UsersLocation
UserID1:Location1
UserID2:Location2
So every time you change your main array you need to change this too.