I want to get a user corresponding to an event
I have a list of Events
let eventsRef = FIRDatabase.database().reference.child("Events")
I have a list of Users
let usersRef = FIRDatabase.database().reference.child("Users")
My Event and User model is as below
Events
Event1
eventHost: user1_uid
Event2
eventHost: user2_uid
Users
User1
email: email1
User2
email: email2
The following callback (in the Event model) is never invoked:
if let userKey = eventData["eventHost"] as? String {
userRef = usersRef.child(userKey)
userRef.observeSingleEvent(of: .value, with: { snapshot in
...
})
}
I can confirm that I have not enabled disk persistence and that user uid is available. Is there anything I am doing obviously wrong?
======
EDIT: The simplified event model
import Foundation
import Firebase
class Event {
// event metadata
private var _eventId: String!
private var _eventHost: User!
var eventId: String {
return _eventId
}
var eventHost: User {
return _eventHost
}
init(eventId: String, eventData: Dictionary<String, Any>) {
self._eventId = eventId
if let userKey = eventData["eventHost"] as? String {
let usersRef = FIRDatabase.database().reference().child("Users")
let userRef = usersRef.child(userKey)
print(userRef)
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
print("USERY: \(snapshot.key)")
if let userDict = snapshot.value! as? Dictionary<String, Any> {
let id = snapshot.key
self._eventHost = User(userId: id, userData: userDict)
}
})
}
}
}
The print(userRef) resolves to
https://xxxx.firebaseio.com/Users/AFHpS3npOga4tfj10GS2HGeT9uJ3`
which is a valid object in my Firebase structure. Snippet of Firebase User structure
"AFHpS3npOga4tfj10GS2HGeT9uJ3" : {
"email" : "test#gmail.com",
"firstName" : "Wilma",
"lastName" : "Flintstone",
"profileImageUrl" : "http://images.iimg.in/c/569f4771c45d324bda8b4660-4-501-0-1453279096/google/user-icon-png-pnglogocom.img",
"provider" : "Firebase",
"userId" : "AFHpS3npOga4tfj10GS2HGeT9uJ3"
},
can you take a look at the rules of your firebase database :
It should be something like this
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
in order to let non authenticated people read / write data you should do the following :
{
"rules": {
".read": true,
".write": true
}
}
From the code you post I don't see any problem ...
If this doesn't work please post more code and tell us what you plan to do exactly so we can better help you.
Edit: To go along with the above suggestion, adding a cancel block to the observe function will reveal if there's a rule issue. If the user cannot access the node, the Xcode console will print 'Permission Denied'
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
print("USERY: \(snapshot.key)")
if let userDict = snapshot.value! as? Dictionary<String, Any> {
let id = snapshot.key
self._eventHost = User(userId: id, userData: userDict)
}
}, withCancel: { error in
print(error.localizedDescription)
})
Related
I am trying to simply fetch a users favourite maps onto a tableview.
something that i thought would be very basic but turned out to be extremely difficult.
The code here is the best that i have managed so far, Attempting to somehow reference a (users id) with a (yourmaps id) to fetch specific information.
For example. Since the user has made 1 map his favourite(with id (-LpY4XEER-b21hwMi9sp)). I want to look through all maps within root["yourmap"] and only fetch his map onto a tableview.
Firebase
"users" {
"6g55cHXH4begwooHQvO4EKNV3xm1" : {
"photoURL" : "https://firebasestorage.googleap...",
"username" : "lbarri",
"yourmaps" : {
"-LpY4XEER-b21hwMi9sp" : true
}
}
}
"yourmaps": {
"-LpY4XEER-b21hwMi9sp" : {
"author" : {
"photoURL" : "https://firebasestorage.googleapis.com/v...",
"uid" : "6g55cHXH4begwooHQvO4EKNV3xm1",
"username" : "lbarri"
},
"mapmoderators" : {
"6g55cHXH4begwooHQvO4EKNV3xm1" : true
},
"mapphotoURL" : "https://firebasestorage.googleapis...",
"mapusername" : "Hello World"
},
"-LpYo_pQ8zIOGHHlNU1Q" : {
"author" : {
"photoURL" : "https://firebasestorage.googleapis.com/v...3",
"uid" : "RLFK9xnvhccTu2hbNHq0v05J2A13",
"username" : "lbarri"
},
"mapmoderators" : {
"RLFK9xnvhccTu2hbNHq0v05J2A13" : true
},
"mapphotoURL" : "https://firebasestorage.googleapis.com/...",
"mapusername" : "Dream"
}
}
Swift
func getCurrentUserMaps() {
guard let userProfile = UserService.currentUserProfile else { return }
let currentUserId = userProfile.uid
let userRef = Database.database().reference().child("users").child(currentUserId)
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
let root = snapshot.value as? NSDictionary
if let mapsByUser = root!["yourmaps"] as? [String: Bool] {
for (documentId, status) in mapsByUser {
if status {
// Document is true, check for the maps
self.fetchyourmaps(key: documentId, owner: currentUserId)
}
}
}
}) { (error) in
print(error.localizedDescription)
}
}
func fetchyourmaps(key:String, owner:String) {
let yourMapRef = Database.database().reference().child("yourmaps")
yourMapRef.observeSingleEvent(of: .value, with: {snapshot in
let user = snapshot.value as? NSDictionary
if let mapsByUser = user!["mapmoderators"] as? [String: Bool] {
for (userId, status) in mapsByUser {
if userId == owner && status == true {
print("Owner \(owner) manages this \(user)")
var tempYourMap = [YourMapProfile]()
for key in (snapshot.value as? NSDictionary)! {
let childSnapshot = key as? DataSnapshot
let dict = childSnapshot!.value as? [String:AnyObject]
let author = dict!["author"] as? [String:AnyObject]
let uid = author!["uid"] as? String
let username = author!["username"] as? String
let photoURL = author!["photoURL"] as? String
let url = URL(string:photoURL!)
let mapusername = dict!["mapusername"] as? String
let mapphotoURL = dict!["mapphotoURL"] as? String
let mapurl = URL(string:mapphotoURL!)
let userProfile = UserProfile(uid: uid!, username: username!, photoURL: url!, mapPoints: mapPoints!)
let yourmapprofile = YourMapProfile(mapid: childSnapshot!.key as! String, mapauthor: userProfile, mapusername: mapusername!, mapphotoURL: mapurl!)
tempYourMap.append(yourmapprofile)
}
self.yourmaps = tempYourMap
self.tableView.reloadData()
}
}
}
})
}
print("Owner \(owner) manages this \(user)") does print the correct maps onto the console
After that line it is when i cant figure out how to package the information to my tableview.
I have searched everywhere for information on how to retrieve data from Firebase when referencing one root folder to another but i cant find anything helpful. So any link/guide/ tutorial etc would be appreciated and i'll gladly take it from there. Is this at least how you are supposed to do it?
There are a few ways to do this but here's two: Option 1 is to leverage a deep query to get the maps that are this users favorites. The second is to iterate over the users maps and pull each one at a time.
Option 1:
Start with a maps node like this
allMaps
map_0
favorite_of
uid_0: true
uid_3: true
map_user_name: "Larry"
map_1
favorite_of
uid_2: true
map_user_name: "Moe"
map_2
favorite_of
uid_0: true
map_user_name: "Curly"
Then, a deep query to get all the favorite maps of uid_0
func queryToGetMyFavoriteMaps() {
let uid = "uid_0"
let ref = self.ref.child("allMaps")
let path = "favorite_of/" + uid
let query = ref.queryOrdered(byChild: path).queryEqual(toValue: true)
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
print(child) //prints the map_0 & map_2 nodes since that's the favorite onces
}
})
}
Option 2
Change up the allMaps node since we won't be doing a query
allMaps
map_0
map_user_name: "Larry"
map_1
map_user_name: "Moe"
map_2
map_user_name: "Curly"
and then the users node will be something like this
users
uid_0
name: "Frank"
favorite_maps:
map_0: true
map_2: true
uid_1
name: "Leroy"
favorite_maps:
map_1: true
and then the code that reads uid_0's favorite_maps node, and gets the keys from that snapshot, and then iterates over them, reading the map nodes one at a time.
func iterateToGetFavoriteMaps() {
let uid = "uid_0"
let userRef = self.ref.child("users").child(uid)
userRef.observeSingleEvent(of: .value, with: { snapshot in
if let mapRefs = snapshot.childSnapshot(forPath: "favorite_maps").value as? [String: Any] {
let mapKeys = mapRefs.keys //note mapKeys is a Dict so we can directly access the keys
for key in mapKeys {
let mapRef = self.ref.child("allMaps").child(key)
mapRef.observeSingleEvent(of: .value, with: { mapSnapshot in
let name = mapSnapshot.childSnapshot(forPath: "mapUserName").value as? String ?? "No Name"
print(name)
})
}
}
})
}
I am trying to list all the users from a firebase node in a table view (this is working) but would then like to remove the current user from the list (this is not working).
I've tried to use removeValue() but it still ran with the current user on the table view - also I don't want to remove the user from firebase
I then tried to make it run only if the the user autoId is not equal to the current users Id but it still shows up on the table view cell
Would appreciate any help :)
My firebase structure is like this:
"users" : {
"8x1SGi2P0KVOKm4i60JQLP1bdU63" : {
"fullname" : "bbbb",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2F8x1SGi2P0KVOKm4i60JQLP1bdU63?alt=media&token=7932b14f-c2d8-46fd-9dd1-c607217fe8d3",
},
"B7rwHiCTlphZjKXfPSEzkIwl8RH2" : {
"fullname" : "Aaaa ",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2FB7rwHiCTlphZjKXfPSEzkIwl8RH2?alt=media&token=072e1f41-935e-430d-af99-dc640381f8e6",
},
"FRuuk20CHrhNlYIBmgN4TTz3Cxn1" : {
"fullname" : "eeee",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2FFRuuk20CHrhNlYIBmgN4TTz3Cxn1?alt=media&token=bf89b903-a51a-4d6d-bdef-fe2667d78842",
},
Code to which lists users:
func observeUsers(completion: #escaping (UserModel) -> Void) {
REF_USERS.observeSingleEvent(of: .childAdded, with: { snapshot in
if let dict = snapshot.value as? [String: Any] {
let user = UserModel.transformUser(dict: dict, key: snapshot.key)
//line below used first to remove value from listing on table view
//Api.User.REF_USERS.child("users").child(Api.User.CURRENT_USER!.uid).removeValue()
//line below - if user autoID is not equal to the current user then list
if user.id != Api.User.CURRENT_USER?.uid {
completion(user)
}
}
})
}
EDIT:
func loadUsers() {
var allUsers = [String]()
Api.User.REF_USERS.observe(.value, with: { snapshot in
for child in snapshot.children { //build the array of keys
let snap = child as! DataSnapshot
let key = snap.key
allUsers.append(key)
print(allUsers)
}
})
}
instead of removing try this
create model of your tabledata
then create an empty array of it
while fetching the data append all except that which has same currentuser.uid
then reload the tableview this will show all the data except the current user
this is the code as promised:
but this need a little modification in your database
make your database like this
"users":{
"childbyautid":{
"fullname": "name",
"profileimageurl": "your url",
"userid": "userid"
}
then you can write like this
var myArr = [String]()
Database.database().reference.child("users").observe(.value){(snapshot) in
if snapshot.childcount > 1 { self.myArr.removeAll()
for data in snapshot.children.allObjects as! [DataSnapshot]{
if let d = data.value as? [string: any]{
if Auth.auth.currentuser.uid != d["userid"]{
myArr.append(d["name"]}else{print("this is the user itself"}}}
You can control this in you loadUsers by adding userId check like below
func loadUsers() {
var allUsers = [String]()
Api.User.REF_USERS.observe(.value, with: { snapshot in
for child in snapshot.children { //build the array of keys
let snap = child as! DataSnapshot
let key = snap.key
if key != currentUser.id{
allUsers.append(key)
}
print(allUsers)
}
})
}
I'm trying to query Firebase to check if the current user's uid is listed in a room's "participants". If so, I grab the info for that room.
Below is my current observer which listens to ALL rooms in the app, not just the rooms the user is a participant of. But I need to perform a check first, to see which rooms the current user's UID is listed in; if there's a match (the uid is in a room's participants), THEN get the data for that room:
private func observeRooms() {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {print("Error getting user UID"); return}
roomRefHandle = roomRef.observe(.childAdded, with: { (snapshot) -> Void in
let roomData = snapshot.value as! Dictionary<String, AnyObject>
let id = snapshot.key
guard let name = roomData["roomName"] as! String! else {print("Error getting user name"); return}
self.usersRooms.append(Room(id: id, name: name, participants: [uid]))
self.tableView.reloadData()
})
}
This is how the rooms are structured in the database:
"rooms" : {
"-Ki6TJWO-2R1L4SyhSqn" : {
"messages" : {
"-Ki6TWrXxWqjaRJAbyVt" : {
"senderId" : "tzfHgGKWLEPzPU9GvkO4XE1QKy53",
"senderName" : "Timothy",
"text" : "Room One message"
}
},
"participants" : {
"tzfHgGKWLEPzPU9GvkO4XE1QKy53" : true
},
"roomName" : "Room One"
},
"-Ki6TKOnmToeUuBzrnbb" : {
"participants" : {
"tzfHgGKWLEPzPU9GvkO4XE1QKy53" : true
},
"roomName" : "Room Two"
},
"-Ki6TLGC1Encm1v-CbHB" : {
"participants" : {
"tzfHgGKWLEPzPU9GvkO4XE1QKy53" : true
},
"roomName" : "Room Three"
}
}
How can I change my function so that it first checks all the room's participants for the current user's uid, before grabbing the values?
Thanks for any suggestions!
EDIT: Jay's approach:
private func observeRooms() {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {print("Error getting user UID"); return}
let queryRef = roomRef.queryOrdered(byChild: "participants/\(uid)").queryEqual(toValue: true)
queryRef.observe(.childAdded, with: { snapshot in
let roomDict = snapshot.value as! [String: AnyObject]
let id = snapshot.key
let roomName = roomDict["roomName"] as! String
let participants = roomDict["participants"] as! [String: AnyObject]
let numberOfParticipants = participants.count
print("\nRoom Name: \(roomName)")
print("Participants: \(participants)")
print("Room ID: \(id)\n")
self.usersRooms.append(Room(id: id, name: roomName, participants: [uid]))
self.tableView.reloadData()
})
}
To keep it super simple, store a reference to the user in each room they belong to.
rooms
room_0
room_name: "My Room"
users
user_1: true
user_2: true
room_1
room_name: "Their Room"
users
user_1: true
Then a simple query which will gather all the needed data, and will also leave an observer attached so if this user joins any new rooms the app will be notified.
let roomsUsersRef = self.ref.child("rooms")
let queryRef = roomsUsersRef.queryOrdered(byChild: "users/user_1").queryEqual(toValue: true)
queryRef.observe(.childAdded, with: { snapshot in
let roomDict = snapshot.value as! [String: AnyObject]
let roomName = roomDict["room_name"] as! String
let usersDict = roomDict["users"] as! [String: AnyObject]
let userCount = usersDict.count
print("Room: \(roomName) has \(userCount) users")
})
and the output
Room: My Room has 2 users
Room: Their Room has 1 users
You could expand on this with .childChanged and .childRemoved to keep track of any events that occur in a room this user belongs to. So if another user joins or leaves a room this user is in, app will be notified; if the owner of the room boots this user from the room, the app will also be notified.
Ideally you would create a separate node in your app to store the information you want. Something like:
{
"usersRooms": {
"tzfHgGKWLEPzPU9GvkO4XE1QKy53": {
"-Ki6TJWO-2R1L4SyhSqn": true,
"-Ki6TKOnmToeUuBzrnbb": true,
"-Ki6TLGC1Encm1v-CbHB": true
}
}
}
This would allow you to get the node for the user and instantly see what rooms they are apart of. Once you've done that you can loop over the results to get the individual rooms. In terms of keeping this list updated look into firebase functions or roll your own.
I'm trying to query my Firebase database to find users of a particular name or email. I've found several examples of how to do this, all of them have seemed relatively easy to follow, but none have worked as expected for me.
Here is an example of how my json data is structured.
{
"allUsers" : {
"uid0001" : {
"userInfo" : {
"email" : "firstName1.lastName1#email.com",
"firstName" : "firstName1",
"lastName" : "lastName1",
"uid" : "uid0001"
}
},
"uid0002" : {
"userInfo" : {
"email" : "firstName2.lastName2#email.com",
"firstName" : "firstName2",
"lastName" : "lastName2",
"uid" : "uid0002"
}
}
}
}
And here is a sample function of how I'm trying to query the database
func performQuery(forName queryText:String)
{
let key = "firstName"
let ref1 = firebaseDatabaseManager.allUsersRef.queryOrdered(byChild: queryText)
let ref2 = firebaseDatabaseManager.allUsersRef.queryEqual(toValue: queryText, childKey: key)
//ref.observeSingleEvent(of: .childAdded, with: {(snapshot) in
ref1.observe(.childAdded, with: {(snapshot) in
let userId = snapshot.key
if let dictionary = snapshot.value as? [String: AnyObject]
{
if let userInfo = dictionary["userInfo"] as? [String:AnyObject]
{
if
let email = userInfo["email"] as? String,
let firstName = userInfo["firstName"] as? String,
let lastName = userInfo["lastName"] as? String
{
let user = User.init(withFirst: firstName, last: lastName, userEmail: email, uid: userId)
}
}
}
})
}
You can see here I have two examples of how I'm structuring ref and two examples of how I'm observing the reference, although I've tried every possible combination that I can think of.
If I'm using ref.observe(....
The block will execute for all users at the node regardless of if queryText is actually present or not.
If I'm using ref.observeSingleEvent(of:....
The block will execute for the topmost user in the json structure.
On top of that, I've tried several variations of reference that return nothing at all.
Any help at all is appreciated!
Thanks
You need to combine queryOrderedByChild: and queryEqualToValue: to get the correct results:
let query = firebaseDatabaseManager.allUsersRef
.queryOrdered(byChild: "userInfo/" + key)
.queryEqual(toValue: queryText)
query.observe(.childAdded, ...
Try replacing
let ref2 = firebaseDatabaseManager.allUsersRef.queryEqual(toValue: queryText, childKey: key)
with
let ref2 = ref1.queryEqual(toValue: queryText)
and then call:
ref2.observe(.childAdded, with: {(snapshot) in
Since right now you are not looking for a certain user but for all users
This issue is the Firebase structure is (unnecessarily) too deep.
What you have is
"allUsers" : {
"uid0001" : {
"userInfo" : { <- This is the issue
"email" : "firstName1.lastName1#email.com",
"firstName" : "firstName1",
"lastName" : "lastName1",
"uid" : "uid0001"
}
},
It should (could) be
"allUsers" : {
"uid0001" : {
"email" : "firstName1.lastName1#email.com",
"firstName" : "firstName1",
"lastName" : "lastName1"
}
}
There's probably no need to have the userInfo node inside the uid0001 node.
Also, you probably don't need the uid stored in the node as well as using it as the key - when the node is returned you can always get the uid from the snapshot.key for each user.
That being said, you can actually do this with a deep query, but it doesn't appear to be needed in this case. (See Frank's answer as it is the correct solution for the structure posted in the question)
and to query for a specific first name using the structure I suggested
let fName = "firstName1"
let queryAllUsersRef = allUsersRef.queryOrdered(byChild: "firstName")
.queryEqual(toValue: fName)
//get all of the users with firstName1
queryRef.observeSingleEvent(of: .value, with: { snapshot in
//snapshot may return more than one user with that first name
// so iterate over the results
for snap in snapshot.children {
let userSnap = snap as! FIRDataSnapshot //each user is it's own snapshot
let userKey = commentSnap.key //the uid key of each user
let userDict = userSnap.value as! [String:AnyObject]
let email = userDict["email"] as! String
print("uid: \(userKey) has email: \(email)"
}
})
I have a view controller for My Profile. Logging in allows the profile page to appear without errors but when signing up, app crashes when pressing the contacts button located at bottom of view controller as seen below.
The process:
User Signs Up:
func signUp(_ email: String, usersname: String, password: String, data: Data!, loginHandler: LoginHandler?) {
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
// Show error to user
self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler)
} else { // success creating user
if user?.uid != nil { // if there is a valid user id
// Store user to database
self.setUserInfo(user, usersname: usersname, email: email, password: password, data: data!)
// Log In the user
self.login(email: email, password: password, loginHandler: loginHandler)
}
}
})
}
As in the signUp(), setUserInfo() is called, which contains images, and then calls saveUser()
Save User
func saveUser(_ user: FIRUser!, usersname: String, email: String, password: String) {
// Create the user dictionary info
let userInfo = ["email": user.email!, "password": password, "usersname": usersname, "uid": user.uid, "photoUrl": String(describing: user.photoURL!)]
// create user reference
let userRef = DataService.Instance.dbRef.child("riders").child(user.uid)
// Save the user info in the database
userRef.setValue(userInfo)
}
Logs In
func login(email: String, password: String, loginHandler: LoginHandler?) {
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
self.handleFirebaseErrors(err: error as! NSError, loginHandler: loginHandler)
} else {
loginHandler?(nil, nil)
}
})
}
The problem here is in saveUser():
At the moment, firebase shows the user.uid but I want it to show the username of the user.
let userRef = DataService.Instance.dbRef.child("riders").child(usersname)
With the above code, once the contacts button is pressed on the RidersVC, it crashes the app with error:
fatal error: unexpectedly found nil while unwrapping an Optional value
on line 56 of MyProfileVC:
let imageUrl = String(user.photoUrl)
Any ideas as how I can get the username to be displayed as the child of "riders" instead of the user.uid without it crashing?
MyProfileVC.swift
if FIRAuth.auth()?.currentUser == nil {
let vc = UIStoryboard(name: "Rider", bundle: nil).instantiateViewController(withIdentifier: "Login")
present(vc, animated: true, completion: nil)
} else {
dbRef.child("riders/\(FIRAuth.auth()!.currentUser!.uid)").observe(.value, with: { (snapshot) in
DispatchQueue.main.async(execute: {
let user = User(snapshot: snapshot)
self.username.text = user.usersname
self.email.text = FIRAuth.auth()?.currentUser?.email
let imageUrl = String(user.photoUrl)
Firebase Database Structure: (how I want it to be)
{
"riders" : {
"rider 1" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"usersname" : "rider 1"
}
}
}
User.swift
struct User {
let usersname: String!
let email: String!
let password: String!
let photoUrl: String!
var ref: FIRDatabaseReference?
var key: String
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
ref = snapshot.ref
let snapshotValueUsersname = snapshot.value as? NSDictionary
usersname = snapshotValueUsersname?["usersname"] as? String
let snapshotValueEmail = snapshot.value as? NSDictionary
email = snapshotValueEmail?["email"] as? String
let snapshotValuePass = snapshot.value as? NSDictionary
password = snapshotValuePass?["password"] as? String
let snapshotValuePhoto = snapshot.value as? NSDictionary
photoUrl = snapshotValuePhoto?["photoUrl"] as? String
}
Firebase structure - (the way it is now)
{
"drivers" : {
"RideRequests" : {
"europeanjunkie" : {
"active" : true,
"latitude" : "45.267",
"longitude" : "-66.059",
"userId" : "5c17ByRJljZFcM703Vqn5eSFwYJ3",
"username" : "europeanjunkie"
}
}
},
"riders" : {
"5c17ByRJljZFcM703Vqn5eSFwYJ3" : {
"email" : "europeanjunkie#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com",
"uid" : "5c17ByRJljZFcM703Vqn5eSFwYJ3",
"usersname" : "europeanjunkie"
}
}
}
Here's some stuff to consider - a little, some or all may get you headed in the right direction. Also, you can probably remove all of the DispatchQueue calls as Firebase does most of the heavy lifting for you, and with proper code structure, they are not needed.
1) A Swifty user class
class UserClass {
var usersname = ""
var email = ""
var password = ""
var photoUrl = ""
var uid = ""
init(withSnapshot: FIRDataSnapshot) {
let dict = withSnapshot.value as! [String:AnyObject]
uid = withSnapshot.key
usersname = dict["usersname"] as! String
email = dict["email"] as! String
password = dict["password"] as! String
photoUrl = dict["photoUrl"] as! String
}
}
note that we are using the var uid of each user to identify them (their 'key')
The structure that matches that class
users
uid_0
email: "bill#email.com"
password: "myPassword"
photoUrl: "http://www.url.com"
usersname: "Bill"
uid_1
email: "leroy#email.com"
password: "aPassword"
photoUrl: "http://www.anotherUrl.com"
usersname: "Leroy"
Notice again the users and their associated info are stored within the /users node in each child node that has that users uid as the key.
And some code that reads in uid_0, prints the uid and name. This code is a one-shot so it reads uid_0, but does NOT leave an observer attached to the node.
let userRef = rootRef.child("users/uid_0")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let aUser = UserClass(withSnapshot: snapshot)
print("uid \(aUser.uid) has name \(aUser.usersname)")
})
Now the Geofire node would like something like this
user_locations
uid_0
//geofire data
uid_1
//geofire data
So now there is a direct correlation between the users node and their location.
In general, it's a good idea to disassociate node names (keys, which are static data) from the data they contain, which is dynamic.
With the structure in the initial question, imagine if 'europeanjunkie' changed his name to 'europeanjunkieDude'. Every place you reference 'europeanjunkie' would then have to be changed - and if it's used as a key, the entire node would have to be read in, deleted, updated, and re-written.
Using child keys created by Firebase, uid's and childByAutoId(), removes that issue.
Hope that helps!
In my opinion, if you want to query the username as the keyword. There are two possible ways to struct your dictionary.
First, use childByAutoId, username and userid will be at the same level, so you can get which value you like.
{
"riders" : {
"-KQaU9lVcUYzIo52LgmN" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"usersname" : "rider 1",
"userid" : "rider 1"
}
}
}
Second, make username as the child of riders. However, there would be tons of Mike.
{
"riders" : {
"username" : {
"email" : "rider1#me.com",
"password" : "whatever",
"photoUrl" : "https://firebasestorage.googleapis.com/...",
"userid" : "rider 1"
}
}
}