Retrieve data from an unknown child name with Firebase and Swift - 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.

Related

Replacing multiple values in Firebase

Is there a way to quickly replace values in a firebase snapshot based on certain criteria. For example, I'm looking to replace all "username" with the value "xyz" where userId = userId_0001 (userId is not unique). This is my code so far:
let databaseRef = Database.database().reference().child("usernames").queryOrdered(byChild: "userId").queryEqual(toValue: "userId_0001")
databaseRef.observe(.value, with: { (snapshot) in
for childSnapshot in snapshot.children {
let username = value?["username"] as? String ?? ""
username.setValue("xyz")
})
}
There are a few issues with the code in the question and the query value in the code (userId_0001) doesn't match the value in the screen shot (userId_001)
From what I gather, you want to query firebase for nodes with a userId of userId_001 (which matches your screenshot) and for those nodes, replace the existing username value with xyz
Here's the code that will do that
func replacer() {
let databaseRef = Database.database().reference().child("usernames").queryOrdered(byChild: "userId").queryEqual(toValue: "userId_0001")
databaseRef.observe(.value, with: { snapshot in
let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
for snap in childSnaps {
snap.ref.child("username").setValue("xyz")
-- or --
snap.ref.updateChildValues(["username": "xyz"])
}
})
}
I includes two options within the for loop. Only use one. The nice thing about updateChildValues is you can replace multiple values within the parent node at once if needed.

Displaying firebase information based on search query [Firebase][Swift]

I have a Firebase Database whereby I'm trying to display 5 random users (with their name and email) by querying them by their age, on 5 different view controllers which are controlled by a UIPageViewController.
I have created the query code to display users by their age. The code is below:
func findoutinfo(){
let usersRef = Database.database().reference().child("Users")
let query = usersRef.queryOrdered(byChild: "Age").queryEqual(toValue: "21")
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let childSnap = child as! DataSnapshot
let dict = childSnap.value as! [String: Any]
let name = dict["Name"] as! String
let email = dict["email"] as! String
print(childSnap.key, name, email)
}
})
}
However, I haven't discovered a way of randomly picking 5 users and display their information on the various pages. Ensuring that all of them are different.
Unfortunately. Firebase doesn't provide you with a simple solution for picking random children. Depending on the use case you might have to go for different approaches.
If the list of Users isn't big, you can get all the users, put them in an array and then pick 5 of them randomly. Something like:
var selectedUsers = [[String: Any]]()
let qtyOfUsersToSelect = 5
var users = getUsersArrayFromFirebase() // Made up function where you should fetch the Users.
for i in 1...5 {
selectedUsers.append(users.remove(at: Int.random(0..<users.count)))
}
If you expect the database users to be big, then I would recommend you using Firebase functions and handling this on the backend.

Firebase grouping of auto generated ID tags

Hello & thanks in advance, using swift 4- After retrieving my Firebase data, i am trying to group everything by Auto generated child ID- the (LKQvTZIe...) parts. My reason for doing this is because the "image, planit, title" all represent one complete post. I need to display the links in a collection view that is tied with the "title" and "planit" parts of the post, so each auto generated ID needs to be tied together.
My question - Is there any way to group or call things by those Auto generated ID's?
That seems like a logical way for me to assure that all 3 of these nodes are grouped together.
THIS IS THE VIEW DID LOAD SECTION
let userID = Auth.auth().currentUser?.uid
ref = Database.database().reference()
//ref.child("planits").observeSingleEvent(of: .value, with: { (snapshot) in
ref.child("planits").observe(.value, with: { (snapshot) in
let FirebaseDataDict = snapshot.value as! [String: AnyObject]
print(FirebaseDataDict)
// THIS GRABS THE EXACT USERS PLANIT DETAILS FROM THE DATA BASE
for child in snapshot.children { //.value can return more than 1 match
let snap = child as! DataSnapshot
let dict = snap.value as? NSDictionary
let senderID = dict!["senderId"]
// IF USER ID EQUALS THE SENDER ID IN DATABASE, THEN UPLOAD THEIR PLANITS
if userID == senderID as! String {
let titleOfPlanit = dict!["title"] as! [String]
let imagesForThisPlanit = dict!["images"] as! [String]
let individualPlanName = dict!["plans"] as! [String]
imagesInPlanit = imagesForThisPlanit
self.nameOfSinglePlan = individualPlanName
self.nameOfThisPlanit.append(contentsOf: titleOfPlanit)
}
}
})
// JSON RESPONSE, FOR INSTANCE - THE FIRST 3 BLOCKS OF CODE BELONG TO A SINGLE PLANIT, THE NEXT 3 BELONG TO THEIR OWN SEPERATE PLANIT
["marketing party "]
["https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F34047334%2F203533422144%2F1%2Foriginal.jpg?h=200&w=450&auto=compress&rect=234%2C0%2C734%2C367&s=26d86a54d46bcbe86ee2a2728f0b89b4", "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F42440910%2F68964867283%2F1%2Foriginal.jpg?h=200&w=450&auto=compress&rect=0%2C318%2C4592%2C2296&s=3aa7bf43a9a2c647e92a6aa5d11ce1bc"]
["Digital Marketing Training in Pomona,CA-USA|Eduscil", "SoulfulofNoise The Tour # Pomona"]
["send "]
["https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F45161425%2F210370190852%2F1%2Foriginal.jpg?h=200&w=450&auto=compress&rect=0%2C4%2C1920%2C960&s=b575da96cc7c5b13b36ba82e666e693a"]
["RRB Dance Company Parivaar Night"]
I do not have any experience in Swift but here's what you should do with Firebase about collecting posts:
When you request a child or child, you can ask for a uid for this posts
Now you can order the parts very normally
If you understand in Android or Java, the calls are as :
ref.child("planits").child(Auth.auth().currentUser?.uid).
ref.child("planits").child(senderid).
You can not post any value with the same name
FireBase creates random names for each new child
If you intend to create a child with the same name in a child, I find that is not possible
You can assemble the rest of the parts in order by Query

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)
}
})

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

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")