Displaying firebase information based on search query [Firebase][Swift] - 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.

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.

How to unpack multiple levels of nested JSON in Firebase Database

In my app, I would regularly have a JSON topic, for example message, then nested in that is a random ID, then the message text as a string inside the random ID. But, I need to decipher multiple levels of random IDs. Is that possible in Firebase for Swift? This is what I mean:
This is my code:
Database.database().reference().child("app").observe(.childAdded) { (snapshot) in
//app is first in the JSON tree
let dict = snapshot.value as! [String: Any]
let msg = dict["message"] as! String
Obviously this is crashing the app, as it's looking for "Message" in the first RandomID. Is there a solution to this? I haven't found resources for specifically what I'm looking for. Thank you.
You'll want to loop over the children of snapshot as shown here:
Database.database().reference().child("app").observe(.childAdded) { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot //downcast
let dict = snap.value as! [String: Any]
let msg = dict["message"] as! String
}
})
Also see:
Get data out of array of Firebase snapshots
Swift Firebase -How to get all the k/v when using queryOrdered(byChild: ).queryEqual(toValue: )
other questions about looping over child nodes

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

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.