I have a Firebase Database structured like this:
results: {
A: [
{data}
],
B: [
{data}
],
C: [
{data}
],
....
}
It is a dictionary of values sorted alphabetically.
My question is, what would be the best way to retrieve this data in swift?
Generally, the most common practice for retrieving Firebase data is to cast the snapshot's value to a Swift Dictionary like this:
let myRef = FIRDatabase.database().reference().child("results")
myRef.observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
// handle data not found
return
}
// data found
let myData = snapshot.value as! [String: Any] // the key is almost always a String
// extracting data from the dictionary
let A = myData["A"] as! [String: Any]
let dataInA = A["anyChildOfA"] as! Double
// ...
})
It doesn't really matter if the data is sorted or not on Firebase, retrieval would be of the same complexity
Update
You can simply loop over all the alphabets to extract the data:
var extractedData = [[String: Any]]() // array of Swift Dictionary
for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters {
let temp = myData[String(c)] as! [String: Any]
extractedData.append(temp);
}
extractedData[0] would be the data in A, extractedData[25] would be the data in Z. That, of course, is assuming you have a child for each letter.
Create a struct to present "data":
struct Data {
...
}
Create a wrapper:
struct DataWrapper {
let data: [Data]
}
Then, create a new model:
struct ModelName {
results: [DataWrapper]
}
Related
I am receiving data from Firestore in the current format;
[(key: "capacity", value: <__NSArrayM 0x600000bd8030>(
32GB,
64GB,
128GB
)
), (key: "condition", value: <__NSArrayM 0x600000bd8180>(
New,
Used
)
)]
Function:
query.getDocuments { snapshot, error in
guard let document = snapshot?.documents else { return }
let flatMap = document.flatMap({ $0.data() })
print(flatMap)
}
I am trying to map this array of [[String: [String]]] into an array of my object such as;
struct Object {
var key: String
var value: [String]
}
How would I go about doing this?
Map method execute a mapping and return an array.
You can think that mapping is an operation to do, in your case you have to transform an element of [String : [String]] in an element of type Object.
Following the map Syntax, you have to apply this transformation only to one element and it will return an array of that elements.
In your case you have just to call the Object init.
let document : [String : [String]] = ["Key1" : ["Value1.0", "Value1.1", "Value1.2"]];
let objects : [Object] = document.map { Object(key: $0.key, value: $0.value) }
print(objects)
JSON Response:
How to map that model classes to Array and how to display them in Table. I am new to swift please help me in this.
This data of departments will receive from my JSON response
{
"content" :
[
{
"Agriculture" :
[
{
"displayName" : "Agri e-Permit",
"downloads" : 3
},
{
"displayName" : "Shri test",
"downloads" : 1
}
]
},
{
"Education" :
[
{
"displayName" : "apple cat",
"downloads" : 1
}
]
}
]
}
My issue is how to create a data model and how to assign values and how to use it in tableView with sections in ViewController is my issue.
*** Here The departments "Agriculture", "Education" and "Municipality" ........ more. It's not constant. we have to take the first index of that array for the department.
Let's start with some basic Structs for our parsed objects. These can later be used to populate our UITableView.
struct Section {
let name: String
let rows: [Row]
}
struct Row {
let displayName: String
let downloads: Int
}
Next lets create some sections from your JSON. The code below is unsafe (lots of ! and is also quite verbose), but should hopefully help explain what you need to do:
// This will hold our final sections for populating the table view
var sections = [Section]()
// This is test code for loading a json file from disk - assume you will get yours from a network call
let url = Bundle.main.url(forResource: "Data", withExtension: ".json")!
let data = try! Data(contentsOf: url)
// This converts the Data object to a Swift Dictionary that we can now use to create our sections
let dict = try! JSONSerialization.jsonObject(with: data, options:.allowFragments) as! [String: Any]
// Each section dictionary is in an array within the json "content"
let contentArray = dict["content"] as! [[String: Any]]
// Loop all section dictionaries in the array.
for sectionDictionary in contentArray {
// Then enumerate inside that dictionary to get the section contents.
for (sectionKey, sectionValue) in sectionDictionary {
// Check we have another array of dictionaries as our value, otherwise bail out.
guard let rowsArray = sectionValue as? [[String: Any]] else { return }
// Use compactMap to build our rows.
let rows: [Row] = rowsArray.compactMap { rowDict in
// Check we have a valid row otherwise bail out.
guard let displayName = rowDict["displayName"] as? String, let downloads = rowDict["downloads"] as? Int else { return nil }
return Row(displayName: displayName, downloads: downloads)
}
let section = Section(name: sectionKey, rows: rows)
sections.append(section)
}
}
You should then have a populated array (sections) ready to use in your table.
I'm trying to pass data that I've retrieved from my firebase database into a field of my singleton. The data is received via closure, and in that closure I'm passing some data into my singleton's properties. If I print the data structure inside the closure (after everything's been assigned) I get the output I'm expecting, but if I print it at the end of the initializer after all the data should've been passed in, it's empty.
import Foundation
import Firebase
class EmployeeList {
static let sharedInstance = EmployeeList()
var employeeDictionary: [String: [EmployeeData]]
var ref: DatabaseReference!
private init() {
employeeDictionary = [String: [EmployeeData]]()
ref = Database.database().reference()
ref.child("employeeList").observeSingleEvent(of: .value, with: { snapshot in
if let dictionary = snapshot.value as? [String: [String: AnyObject]] {
for subsection in dictionary {
var subsectionEmployees: [EmployeeData] = []
for item in subsection.value {
self.ref.child("employeeList/\(subsection.key)/\(item.key)").observeSingleEvent(of: .value, with: { employeeSnapshot in
let employeeObject = EmployeeData(snapshot: employeeSnapshot)
subsectionEmployees.append(employeeObject)
self.employeeDictionary[subsection.key] = subsectionEmployees
//print(self.employeeDictionary) This print statement prints out the expected data every time another employee is appended
})
}
}
}
//print(self.employeeDictionary) This print statement prints an empty data structure
})
}
}
get data from Firebase as Below
var messagedata = [String:AnyObject]()
let databaseReff = Database.database().reference().child("message")
databaseReff.queryOrdered(byChild: "fromId").queryEqual(toValue: self.recieverId).observe(.value, with: { snapshot in
if snapshot.exists(){
self.messagedata = snapshot.value! as! [String : AnyObject]
self.getAllMessagesSent(snapshot: self.messagedata)
} else
self.getAllMessagesSent(snapshot: self.messagedata) //Function Created
}
})
pass the data fetched from Clousre to a dictionary and pass that dict to a function and do anything you want to do or use escaping blocks
func getAllMessagesSent(snapshot: [String:AnyObject]) {
//data is here
}
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.
I'm having issue getting data from Firebase.
schema is
{
title: "dog",
images: {
main: "dog.png",
others: {
0: "1.png",
1: "2.png",
2: "3.png"
}
}
}
how can i parse FDataSnapshot to swift model??
Firebase is a NoSQL JSON database and has no schema and no tables. Data is stored with a 'tree' structure with nodes; parents and children.
You don't need to parse Firebase JSON data to access it, you can access it directly.
FDataSnapshots contain a .key, which is it's parent key in Firebase and .value. .Value may contain one node, or multiple nodes. The Value will have key:value pairs representing the data within the snapshot
So for your example you will have a Firebase structure like this
dogs
dog_id_0
title: "dog"
type: "Alaskan Malamute"
images:
main: "dog.png"
others:
0: "1.png"
1: "2.png"
dog_id_1
title: "another dog"
type: "Boxer"
images:
main: "another_dog.png"
others:
0: "3.png"
1: "4.png"
So, say you want to read in each dog_id_x node one at a time and print some values.
var ref = Firebase(url:"https://your-app.firebaseio.com/dogs")
ref.observeEventType(.ChildAdded, withBlock: { snapshot in
println(snapshot.value.objectForKey("title"))
println(snapshot.value.objectForKey("type"))
})
This will output
dog
Alaskan Malamute
another dog
Boxer
The dog_id_0 and dog_id_1 are node names created with the Firebase childByAutoId.
You could just as easily create a Dog class, and pass it the FDataSnapshot which will populate the class from the data within the snapshot.
February 2017 Update, Swift 3 Xcode 8
Since a lot of things with Swift3 and Firebase have changed by the time this question was asked I will provide an updated way to parse Firebase data:
let userID = FIRAuth.auth()?.currentUser?.uid
//I am registering to listen to a specific answer to appear
self.ref.child("queryResponse").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
//in my case the answer is of type array so I can cast it like this, should also work with NSDictionary or NSNumber
if let snapshotValue = snapshot.value as? NSArray{
//then I iterate over the values
for snapDict in snapshotValue{
//and I cast the objects to swift Dictionaries
let dict = snapDict as! Dictionary<String, Any>
}
}
}) { (error) in
print(error.localizedDescription)
}
Try to play with this:
func makeItems(from snapshot: DataSnapshot) -> [SimpleItem] {
var items = [SimpleItem]()
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
let item = SimpleItem(parentKey: snap.key, dictionary: postDictionary)
items.append(item)
}
}
}
return items
}
func loadItems() {
firebaseService.databaseReference
.child("items")
.queryOrdered(byChild: "date")
.queryLimited(toLast: 5)
.observeSingleEvent(of: .value) { snapshot in
let items = self.makeItems(from: snapshot)
print("🧀 \(items)")
}
}
class SimpleItem {
var parentKey: String?
var id: String?
var description: String?
init(parentKey: String, dictionary: [String : AnyObject]) {
self.parentKey = parentKey
id = dictionary["id"] as? String
description = dictionary["description"] as? String
}
}
You could parse it maually with Dictionary or you can use my library.
Example code for your case:
func main(){
let root=SnapshotParser().parse(snap: Snapshot, type: Root.self)
}
class Root: ParsableObject {
var title:String?=nil
var images:Images?=nil
required init(){}
func bindProperties(binder: SnapshotParser.Binder) {
binder.bindField(name: "title", field: &title)
binder.bindObject(name: "images", field: &images)
}
}
class Images: ParsableObject {
var main:String?=nil
var others:[Int:String]?=nil
required init(){}
func bindProperties(binder: SnapshotParser.Binder) {
binder.bindField(name: "main", field: &main)
binder.bindDictionary(name: "others", dict: &others)
}
}
This will parse all the snapshot children in the single object and convert it in array and you can easily parse the array of children with index
if let snap = snapshot.children.allObjects as? [DataSnapshot]{
print(snap)
for (index,val) in snap.enumerated(){
print("values")
print(val)
print(val.value)
}
}