Retrieve Firebase data given a specific field - ios

I am using Firebase and my database looks like this:
Users
user1
email: "example1#test.com"
password: "pass1"
display name: "Name1"
user2
email: "example2#test.com"
password: "pass2"
display name: "Name2"
How can I retrieve the email for example, given the display name using Swift 3? (e.g., if I know Name1, the retrieved data will be example1#test.com.)

Use firebase as below
let dbstrPath : String! = "Users/user1"
self.dbRef.child(dbstrPath).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
print(snapshot.value!)
// Here you got user value in dict
}
})

Implement the following helper function:
func queryEmail(of displayName: String, completion: #escaping (String?) -> Void) {
let users = FIRDatabase.database().reference().child("Users")
let query = users.queryOrdered(byChild: "display name").queryEqual(toValue: displayName)
query.observeSingleEvent(of: .value) {
(snapshot: FIRDataSnapshot) in
guard snapshot.exists() else {
completion(nil)
return
}
let users = snapshot.children.allObjects as! [FIRDataSnapshot]
precondition(users.count == 1, "Display name isn't unique!")
let userProperties = users.first!.value as! [String: Any]
completion(userProperties["email"] as? String)
}
}
and use it like this:
queryEmail(of: "Name1") {
(email) in
if let email = email {
print("Name1 email is \(email)")
} else {
print("Email not found")
}
}

Related

Getting firebase data for each string in an array

In my Firebase Realtime Database, I have a node labelled "groups" and this is how I constructed it:
Underneath the "users" above, I'm trying to use those userIds to reference the data within each user. This is how I constructed each "users" node I'm trying to reference:
In the below code snippet, I get the userIds from a snapshot of the groups' users child node. And then I run a for-in loop on those userIds to access the information in the "users" node.
The print("This should be the individual userId: ", userId) statement prints out each userId correctly. And the userRef.observeSingleEvent(of: .value, with: { (snapshot) in gets called the first time the for-in loop is called, but it's almost like it's ignored. The app crashes because the user array comes up empty at the end. However, a ridiculous amount of empty users show up in the array (when looking at the Variables View in the Debug Area). So, i feel like I'm running some form of a redundant loop or something.
guard let groupChatPartnerId = message.chatPartnerId() else {
return
}
var users: [User]?
let ref = Database.database().reference().child("groups").child(groupChatPartnerId)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
let groupId = snapshot.key
let groupName = snapshot.childSnapshot(forPath: "groupName").value as! String
let userIdDictionary = snapshot.childSnapshot(forPath: "users").value as! Dictionary<String,AnyObject>
let userIds = Array(userIdDictionary.keys)
print("userIds: ", userIds)
for userId in userIds {
print("This should be the individual userId: ", userId)
let userRef = Database.database().reference().child("users").child(userId)
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
print("This is the snapshot: ", snapshot)
let email: String = snapshot.childSnapshot(forPath: "email").value as! String
print("user's email: ", email)
let uid = snapshot.key
let username = snapshot.childSnapshot(forPath: "username").value as! String
let profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String
let user = User(uid: uid, userUsername: username, userProfileImageUrl: profileImageUrl, userEmail: email)
users?.append(user)
print("user to append to users: ", user)
}, withCancel: nil)
}
print("users :", users)
let group = Group(groupId: groupId, groupName: groupName, users: users!)
self.showChatControllerForGroup(group: group)
}, withCancel: nil)
Let me know if you need any other information. Thanks in advance!
All data is loaded from Firebase asynchronously By the time your print users, none of the userRef.observeSingleEvent has completed yet. So the code to print all users must be inside the completion handle of userRef.observeSingleEvent and must only run once all users have been loaded.
A simple way to do that is to compare the length of users with the length of userIds. If they're the same, you've loaded all users:
for userId in userIds {
print("This should be the individual userId: ", userId)
let userRef = Database.database().reference().child("users").child(userId)
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
print("This is the snapshot: ", snapshot)
let email: String = snapshot.childSnapshot(forPath: "email").value as! String
print("user's email: ", email)
let uid = snapshot.key
let username = snapshot.childSnapshot(forPath: "username").value as! String
let profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String
let user = User(uid: uid, userUsername: username, userProfileImageUrl: profileImageUrl, userEmail: email)
users?.append(user)
print("user to append to users: ", user)
if userIds.count == users.count {
print("users :", users)
}
}, withCancel: nil)
}

How to exclude a specific userID (user) from the database in Firebase with Swift

I am working on the user profile page of my app, where the user can make changes to the user info, like change their username, name... Each user has their own unique username, I have done that with the following code:
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
This checks if there is a user with the same username. Calling this function:
checkUsernameUnique(newUserName: username) { isExist in
if isExist {
print("Username is taken")
} else {
print("Username is not taken")
}
}
The problem with this is that this checks if there is a user using the same username with all the other users in the database, including the current user. How do I exclude the current user?
Code that I tried with the help of one of the answers
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
if let userID = Auth.auth().currentUser?.uid {
print(userID)
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if !snapshot.exists() {
completion(false)
} else {
//Here we will check the given user's UID
snapshot.ref.child("UserID").observeSingleEvent(of: .value, with: { (uidSnapshot) in
//This forced cast should never fail
let uid = uidSnapshot.value as! String
print(uid)
//Now we use FirebaseAuth to cross reference the current user's UID with whatever the "Username" node's sibling node "UserID" is
if Auth.auth().currentUser!.uid == uid {
//The returned user is the same as the current user
completion(false)
} else {
//The returned user is not the same as the current user
completion(true)
}
})
}
})
} else {
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
}
Try this. All we have to do is get the userID of whatever is returned from the query, and check if it equals the current user's uid.
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
guard let json = snapshot.value as? [String:[String:Any]] else {
completion(false)
return
}
//Assuming there will never be more than one database entry with this username, this first element (result) can be unwrapped explicitly without crashing
let result = json.first!.value
let userID = result["UserID"] as! String
if Auth.auth().currentUser!.uid == uid {
completion(false)
} else {
completion(true)
}
})
}
There is no way to conditionally exclude data from a query. You will have to check in your client code if specific data is present in the result, and exclude it from there. Just checking snapshot.exists will not be sufficient in your case - instead, look inside the snapshot to see if it contains the UID of the current user.

Advice on structuring an app

I am not positive if I am structuring my app correctly. I am using structs for the first time and I am trying to save locations from users and create users using Firebase. I want to display all users only by location. The Global.refString gets set from a UIPicker which is hard coded with 6 different locations. loadUserInfo() is not returning any information. It worked the first time I tried it but after reopening and closing the app it always returns empty. Im not sure if a struct will get saved each time I open the app. Should I use a different method to accomplish these tasks.
private func saveUserInfo(firstLastName: String, user: User!, location: String, biography: String, password: String, phoneNumber: String){
let locationRef = Global.refString
let userInfo = ["firstLastName": firstLastName, "email": user.email!, "password": password, "location": location, "phoneNumber": phoneNumber, "biography": biography, "uid": user.uid, "photoURL": String(describing: user.photoURL!)] as [String : Any]
let userRef = dataBaseRef.child(locationRef!).child(user.uid)
userRef.setValue(userInfo) { (error, ref) in
if error == nil{
print("USER SAVED")
self.logIn(email: user.email!, password: password)
}else{
print(error?.localizedDescription)
}
}
}
func loadUserInfo(){
let locationRef = Global.refString
let userRef = dataBaseRef.child(locationRef!).child(Auth.auth().currentUser!.uid)
userRef.observe(.value, with: { (snapshot) in
let user = Users(snapshot: snapshot)
if let username = user.name{
self.nameLabel.text = username
}
if let number = user.phoneNumber{
self.phone = Int(number)
}
if let userLocation = user.location{
self.bioLabel.text = userLocation
}
self.storageRef.storage.reference(forURL: imageOld).getData(maxSize: 10 * 1024 * 1024, completion: { (imgData, error) in
if error == nil {
DispatchQueue.main.async {
if let data = imgData {
self.avatar.image = UIImage(data: data)
}
}
}else {
print(error!.localizedDescription)
}
}
)}
}) { (error) in
print(error.localizedDescription)
}
}
}
struct Global
{
static var Location : String!
static var usersListSent
= [String]()
static var refString: String!
}
Try:
Database.database().reference().child(Global.refString).child(id).observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
print(snap)
}
}

Fetching Firebase Records Based on Email

I am trying to fetch all the driveways which belongs to user using their email as the search key.
And here is the code I am writing:
guard let currentUser = FIRAuth.auth()?.currentUser else {
return
}
let query = FIRDatabase.database().reference(withPath :"driveways").queryEqual(toValue: currentUser.email!, childKey: "email")
query.observe(.value, with: { (snapshot) in
print(snapshot)
})
How can I get all the driveways based on user's email address?
Try this (Swift 3 Firebase 3)
let email = "johndoe#gmail.com"
let queryRef = drivewaysRef.queryOrdered(byChild: "email")
.queryEqual(toValue: email)
queryRef.observeSingleEvent(of: .value, with: { snapshot in
for snap in snapshot.children {
let driveSnap = snap as! FIRDataSnapshot
let driveDict = driveSnap.value as! [String:AnyObject] //driveway child data
let city = driveDict["city"] as! String
let state = driveDict["state"] as! String
print("email: \(email) city: \(city) state: \(state)")
}
})

Firebase Retrieving Data in Swift

I'm trying to retrieve specific data from just the currently logged in user. My data in my database looks like this:
For example, I want to just grab the full_name and save it in a variable userName. Below is what I'm using to grab my data
ref.queryOrderedByChild("full_name").queryEqualToValue("userIdentifier").observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
print(snapshot.value)
// let userName = snapshot.value["full_name"] as! String
})
Unfortunately, this is what my console prints.
I would appreciate any help :) Thank you!
It gives you that warning message indexOn because you are doing a query.
you should define the keys you will be indexing on via the .indexOn
rule in your Security and Firebase Rules. While you are allowed to
create these queries ad-hoc on the client, you will see greatly
improved performance when using .indexOn
As you know the name you are looking for you can directly go to that node, without a query.
let ref:FIRDatabaseReference! // your ref ie. root.child("users").child("stephenwarren001#yahoo.com")
// only need to fetch once so use single event
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if !snapshot.exists() { return }
//print(snapshot)
if let userName = snapshot.value["full_name"] as? String {
print(userName)
}
if let email = snapshot.value["email"] as? String {
print(email)
}
// can also use
// snapshot.childSnapshotForPath("full_name").value as! String
})
Swift 4
let ref = Database.database().reference(withPath: "user")
ref.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() { return }
print(snapshot) // Its print all values including Snap (User)
print(snapshot.value!)
let username = snapshot.childSnapshot(forPath: "full_name").value
print(username!)
})
{
"rules": {
"tbl_name": {
".indexOn": ["field_name1", "field_name2"]
},
".read": true,
".write": true
}
}
You can apply indexOn on any field. Add this json in rules security and rules tab.
Hope this works for you. :)
It retrieves logged in user data:
let ref = FIRDatabase.database().reference(fromURL: "DATABASE_URl")
let userID = FIRAuth.auth()?.currentUser?.uid
let usersRef = ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
let ref = Database.database().reference().child("users/stephenwarren001#yahoo.com")
ref.observeSingleEvent(of: .value, with: { (snap : DataSnapshot) in
print("\(String(describing: snap.value))")
}) { (err: Error) in
print("\(err.localizedDescription)")
}
var refDatabase = DatabaseReference()
refDatabase = Database.database().reference().child("users");
let refUserIdChild = refDatabase.child("stephenwarren001#yahoo.com")
refUserIdChild.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() { return }
print(snapshot) // Its print all values including Snap (User)
print(snapshot.value!)
if let tempDic : Dictionary = snapshot.value as? Dictionary<String,Any>
{
if let userName = tempDic["full_name"] as? String {
self.tfName.text = userName
}
if let email = tempDic["email"] as? String {
self.tfEmail.text = email
}
}
})

Resources