retrieve array elements from firebase in swift - ios

I am completely new to swift and firebase, and I am having difficulties in retrieving array-elements from firebase database
So this is my firebase database
I can retrieve the other elements like this:
database reference
class ViewController: UIViewController {
var ref: FIRDatabaseReference?
let fileName : String = "jsonFile"
method
func parseFirebaseResponse() {
ref?.child("Vandreture").child(fileName).observe(.value, with:
{ (snapshot) in
let dict = snapshot.value as? [String: AnyObject]
let navn = dict!["navn"] as? String
print(navn as Any)
let type = dict!["type"] as? String
print(type as Any)
let Længde = dict!["length"] as? String
print(Længde as Any)
let link = dict!["link"] as? String
print(link as Any)
})
}
the console shows the result
But I have searched for a way to retrieve longitude/latitude pairs,
The first pair should be
latitude 109.987
longitude 102.987
- but so far without luck - help would really be appreciated :)

I think you should restructure your database to something like this:
Vandreture {
jsonFile {
length: "16.2"
link: "www.second.com"
navn: "Kagerup rundt"
positions {
-KqXukxnw3mL38oPeI4y {
x: "102.987"
y: "109.987"
}
-KqXukxnw3mL38oPeI5- {
x: "108.234"
y: "99.098"
}
}
}
}
Then getting your coordinates would be far easier!

Get your "position" as a dictionary (aka [String: AnyObject]).
Then get array of latitude and longitude. Then map of each element from latitude and longitude into a tuple or something like that.
guard let position = dict!["position"] as? [String: AnyObject],
let latitudeArray = position["latitude"] as? [String],
let longitudeArray = position["longitude"] as? [String] else { return }
print(latitudeArray)
print(longitudeArray)

thanks Victor Apeland - now I changed the structure of the database. I was not able to do it exactly as you suggested!!
I concatenated the lon/lat as a string (not the best - i know - I'm a newbie to swift, and firebase is not well documented)
to retrieve the individual elements from my long/lat, I used this method, and I was particular interested in the first reading, so I made a list, populated it, and got the first element, parsing it to a new method
func responsePosition() {
var positions = [String]()
ref?.child("Vandreture").child(fileName).child("position").observe(.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
positions.append(userDict)
}
let pos : String = positions[0]
self.formatPositions(pos : pos)
})
}
In my firebase lon-lat was divided by a space, so I split the string and cast to double.
func formatPositions(pos : String) {
let lotLangDivided = pos.components(separatedBy: " ")
let longitude = Double(lotLangDivided[0])
let latitude = Double(lotLangDivided[1])
}
now I got the result i wanted
- thanks for the help Victor and Khuong :)

Related

Swift 3 Firebase retrieving key and passing to view controller

I've spend hours looking at identical questions but none of the answers I've found are helping this issue. Simple app retrieves data from Firebase Database and passes to another view controller from the tableview. The main data will pass through but I can't edit the information without an identifying "key" which I tried to set as childByAutoID() but then changed to a timestamp. Regardless of the method, all I get is the entries info not the actual key itself.
func loadData() {
self.itemList.removeAll()
let ref = FIRDatabase.database().reference()
ref.child(userID!).child("MyStuff").observeSingleEvent(of: .value, with: { (snapshot) in
if let todoDict = snapshot.value as? [String:AnyObject] {
for (_,todoElement) in todoDict {
let todo = TheItems()
todo.itemName = todoElement["itemName"] as? String
todo.itemExpires = todoElement["itemExpires"] as? String
todo.itemType = todoElement["itemType"] as? String
self.itemList.append(todo)
print (snapshot.key);
}
}
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
If your data looks like this:
Uid: {
MyStuff: {
AutoID: {
itemName: “Apocalypse”,
itemExpires: “December 21, 2012”,
itemType: “Catastrophic”
}
}
}
Then I would query like this:
ref.child(userID!).child("MyStuff").observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let child = child as? DataSnapshot
let key = child?.key as? String
if let todoElement = child?.value as? [String: Any] {
let todo = TheItems()
todo.itemName = todoElement["itemName"] as? String
todo.itemExpires = todoElement["itemExpires"] as? String
todo.itemType = todoElement["itemType"] as? String
self.itemList.append(todo)
self.tableView.reloadData()
}
}
})
Additionally, like I said in my comment you can just upload the key with the data if you’re using .updateChildValues(). Example:
let key = ref.child("userID!").childByAutoId().key
let feed = ["key": key,
“itemName”: itemName] as [String: Any]
let post = ["\(key)" : feed]
ref.child("userID").child("MyStuff").updateChildValues(post) // might want a completionBlock
Then you can get the key the same way you are getting the rest of the values. So your new data would look like this:
Uid: {
MyStuff: {
AutoID: {
itemName: “Apocalypse”,
itemExpires: “December 21, 2012”,
itemType: “Catastrophic”,
key: “autoID”
}
}
}
The key you are trying to look for is located in the iterator of your for loop
Inside your if-let, try to do this:
for (key,todoElement) in todoDict {
print(key) // this is your childByAutoId key
}
This should solve the problem. Otherwise show us a screen of your database structure

Sorting Firebase Realtime Database data in Swift

I need to show these data in a table view, but they have been on the table view in mixing order. How can I put them in the same order as in the database. Please help, I will deeply appreciated.
First image shows my iPhone screen after running the project, second one is the database. I want them exact order as in the database.
I hope periods objects look like this:
struct PeriodItem {
let key: String
let periodEnd: String
let periodName: String
let periodStart: String
let ref: FIRDatabaseReference?
init(periodEnd: String, periodName: String, periodStart: String, key: String = "") {
self.key = key
self.periodEnd = periodEnd
self.periodName = periodName
self.periodStart = periodStart
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
periodEnd = snapshotValue["periodEnd"] as! String
periodName = snapshotValue["periodName"] as! String
periodStart = snapshotValue["periodStart"] as! String
ref = snapshot.ref
}
func toAnyObject() -> Any {
return [
"periodEnd": periodEnd,
"periodName": periodName,
"periodStart": periodStart,
"key": key
]
}
}
So
When you fill your array of Periods fully, just use sorting:
// periods - array of objects from firebase database
let yourTableViewPeriodsArray = periods.sorted(by: { $0.key < $1.key }) // maybe ">" instead of "<"
Then:
DispatchQueue.main.async {
self.tableView.reloadData()
}
Hope it helps.

Retrieve array of dictionary from Firebase & Swift 3

I have a json database on firebase and trying to get them and put into local array of dictionaries.
My json model on Firebase
My struct model is also like below
struct Places {
var type:String!
var country:String!
var name:String!
var image:String!
var coords:[Coords]!
init(type: String, country: String, name: String, image: String, coords: [Coords]) {
self.type = type
self.country = country
self.name = name
self.image = image
self.coords = coords
}
init(snapshot: FIRDataSnapshot) {
let snapshotValue = snapshot.value as! [String:Any]
type = snapshotValue["type"] as! String
country = snapshotValue["country"] as! String
name = snapshotValue["name"] as! String
image = snapshotValue["image"] as! String
coords = snapshotValue["coords"] as! [Coords]!
}
}
And also [Coords] struct model like below:
struct Coords {
var latStart:String!
var latEnd:String!
var lonStart:String!
var lonEnd:String!
init(latStart: String, latEnd: String, lonStart: String, lonEnd: String) {
self.latStart = latStart
self.latEnd = latEnd
self.lonStart = lonStart
self.lonEnd = lonEnd
}
}
And I am trying to get and put json data by below code:
placesRef.observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
print("data not exist")
return
}
var plc: [Places] = []
for eachPlace in (snapshot.children){
let place = Places(snapshot: eachPlace as! FIRDataSnapshot)
plc.append(place)
}
self.allPlaces = plc
The problem is that I can get the array of dictionary except coords dictionary inside array of dictionary. [Coords] dictionary seems null and I would like to know what the problem is. Thanks for any suggestion.
Because snapshotValue["coords"] as! [Coords]! are not Coords yet. They are just dictionaries. You have to go through each dictionary in snapshotValue[“coords”] and init a Coords object, then when you’re finished group them all into an array and assign it to self.coords of the Places struct. The map function is really convenient for this.
Example:
I would change the Coords init function to something like:
init(dictionary: [String : AnyObject]) {
self.latStart = dictionary["lat1"] as? String
//...
//...
}
Then in Places init use something like:
coords = (snapshotValue["coords"] as? [[String : AnyObject]])?.map({ Coord(dictionary: $0) })
I didn't test this and making some assumptions here, but you should be able to make something similar work.

Nested Firebase data for TableView

I'm having a little trouble accessing and saving nested Firebase data.
Here is how my database is set up:
How would I get Bike and Popsicle into an array as well as getting country and price in 2 other arrays? I will be using these arrays to populate a TableView.
Try something like this:
let ref = FIRDatabase.database().reference().child("Test")
ref.observeSingleEvent(of: .value, with: { snapshot in
if let data = snapshot.value as? [String : [String : NSNumber]] {
let bikePopsicleArray = Array(data.keys)
let countryArray = [String]()
let pricesArray = [NSNumber]()
for (key, value) in data.values {
countryArray.append(key)
pricesArray.append(value)
}
}
})
Not sure if this will work but give it a try, let me know how it goes.

how to retrieve child(array) inside another firebase child

I am trying to print array from the firebase. Actually if we tap a medication in a list(tableviewcontroller), it will show its specfic dosages. I got stucked to retrieve the dosages list. Here is my code to get data from firebase. Any help is appreciated. Thanks in advance. My firebase structure looks like this.. firebase img
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observeEventType(.Value, withBlock: { snapshot in
for item in snapshot.children{
FIRDatabase.database().reference().child("medication").child("options").observeEventType(.Value, withBlock: {snapshot in
print(snapshot.value)
})
}
})
You should take a look on firebase documentation https://firebase.google.com/docs/database/ios/read-and-write
but if I'm understanding your idea, you probably has a model class for your medications. So, to retrieve your data you should do like this for Swift 3.0:
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observe(.value, with: { (snapshot) in
for item in snapshot.children{
// here you have the objects that contains your medications
let value = item.value as? NSDictionary
let name = value?["name"] as? String ?? ""
let dossage = value?["dossage"] as? String ?? ""
let type = value?["type"] as? String ?? ""
let options = value?["options"] as? [String] ?? ""
let medication = Medication(name: name, dossage: dossage, type: type, options: options)
// now you populate your medications array
yourArrayOfMedications.append(medication)
}
yourTableView.reloadData()
})
}
Now that you have your array with all your medications, you just need to populate your tableView with this medications. When someone press an item on table you can just call prepareForSegue: and send your yourArrayOfMedications[indexPath.row].options to the next view
The solution is same as above but with a small change.
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observe(.value, with: { (snapshot) in
for item in snapshot.children{
// here you have the objects that contains your medications
let value = item.value as? NSDictionary
let name = value?["name"] as? String ?? ""
let dossage = value?["dossage"] as? String ?? ""
let type = value?["type"] as? String ?? ""
let options = value?["options"] as? [String : String] ?? [:]
print(options["first"]) // -> this will print 100 as per your image
// Similarly you can add do whatever you want with this data
let medication = Medication(name: name, dossage: dossage, type: type, options: options)
// now you populate your medications array
yourArrayOfMedications.append(medication)
}
yourTableView.reloadData()
})
}

Resources