How to store custom object in Firebase with Swift? - swift

I'm porting an android app and using firebase in android it is possible to save a format in this way.
How can i do this on Swift? I read that i can store only this kind of data
NSString
NSNumber
NSDictionary
NSArray
How can I store the obj in atomic operation?
It's correct to store every field of the user object in separate action?
Firebase on Android
mDatabaseReferences.child("users").child(user.getUuid()).setValue(user)

I generally store objects as dictionaries on firebase. If, within my application, I have a User object, and it has properties as such:
class User {
var username = ""
var email = ""
var userID = ""
var consecutiveDaysLoggedOn = Int()
}
let newUser = User()
newUser.username = "LeviYoder"
newUser.email = "LeviYoder#LeviYoder.com"
newUser.userID = "L735F802847A-"
newUser.consecutiveDaysLoggedOn = 1
I would just store those properties as a dictionary, and write that dictionary to my firebase database:
let userInfoDictionary = ["username" : newUser.username
"email" : newUser.email
"userID" : newUser.userID
"consecutiveDaysLoggedOn" : newUser.consecutiveDaysLoggedOn]
let ref = Database.database().reference.child("UserInfo").child("SpecificUserFolder")
// ref.setValue(userInfoDictionary) { (error:Error?, ref:DatabaseReference) in
ref.setValue(userInfoDictionary, withCompletionBlock: { err, ref in
if let error = err {
print("userInfoDictionary was not saved: \(error.localizedDescription)")
} else {
print("userInfoDictionary saved successfully!")
}
}
Does that address your question?

I come with a little extension used to convert a standard SwiftObject in readable dictionnary for FireStore:
extension Encodable {
var toDictionnary: [String : Any]? {
guard let data = try? JSONEncoder().encode(self) else {
return nil
}
return try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
}
}
For example, in my model:
struct Order: Encodable {
let symbol: String
let shares: Int
let price: Float
let userID: String
}
Called with this line:
let dictionnary = order.toDictionnary
This is the kind of dictionary generated
4 elements
▿ 0 : 2 elements
- key : "symbol"
- value : FP.PAR
▿ 1 : 2 elements
- key : "shares"
- value : 10
▿ 2 : 2 elements
- key : "userID"
- value : fake_id
▿ 3 : 2 elements
- key : "price"
- value : 100

Use
self.ref.child("users").child(user.uid).setValue(["username": username])

Related

Get child of dictionary with unknown parent key

I have a dictionary from type [String: Any] that looks like this
"arExtensions" : {
"images" : {
"-LmgO2yG_TWbfOM4Y8X3" : {
"imagePath" : "https://firebasestorage.googleapis.com/v0/b/gpk-citycards.appspot.com/o/ARResources%2F78E88F6D-52F0-43A3-B585-9760D19F0B81?alt=media&token=be3a664f-a94b-4ead-bea4-1197155c016e",
"position" : "bottom"
},
"-LmgO4qaMKupHZIAEoLk" : {
"imagePath" : "https://firebasestorage.googleapis.com/v0/b/gpk-citycards.appspot.com/o/ARResources%2FC7303CF9-0E86-4DC6-A5F5-2761537F0A30?alt=media&token=1f928774-8221-474b-881e-7f395e439131",
"position" : "rightMiddle"
},
"-LmgO9vLT8rEx9Ndog4S" : {
"imagePath" : "https://firebasestorage.googleapis.com/v0/b/gpk-citycards.appspot.com/o/ARResources%2F9132B5B6-E904-4BCE-B56A-0271CB901A7D?alt=media&token=bd66cd1d-494b-4a82-8d74-6e00ac8c8ae6",
"position" : "leftMiddle"
}
}
}
I want to add the images into an object.
var imageObjects: [ImageObject] = []
I know that I can get the values with the keys like this
let dictImages: [String: Any] = dictArExtensions["images"] as! [String : Any]
unfortunately I don't know the key of the children of images.
with two iteration, first to get the key, second to get the needed values i solved the problem like this
var imageKeys: [String] = []
for dict in dictImages{
print(dict.key)
imageKeys.append(dict.key)
print(dict.value)
}
for keys in imageKeys{
let dictImage: [String: Any] = dictImages[keys] as! [String : Any]
let imagePath = dictImage["imagePath"] as? String
let position = dictImage["position"] as? String
imageObjects.append(ImageObject(imagePath: imagePath!, position: position!))
}
but, it seems like a bad solution.
Is there a better or rather more professional solution to this?
You can enumerate the dictionary very simply with key and value but the key is actually unused.
And if you declare the child dictionary as [String:String] you can get rid of the type cast
for (_, value) in dictImages {
let dictImage = value as! [String:String]
let imagePath = dictImage["imagePath"]
let position = dictImage["position"]
imageObjects.append(ImageObject(imagePath: imagePath!, position: position!))
}
Please read the section about dictionaries in the Language Guide

Grab data saved in Firebase and present it on view controller [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Edit (I hope this is more specific):
I can't seem to get the data from firebase to show up the page when i run the app:
When a notification is saved under a child node on firebase, an 'objectId' is printed - I want to grab the data under the node that matches this objectId under another node called 'pinion', a snippet of the JSON firebase structure is:
"notification" : {
"Gmg1ojNoBiedFPRNSL4sBZz2gSx2" : {
"-L_xNVcs7f3RhuLAcg7j" : {
"from" : "Gmg1ojNoBiedFPRNSL4sBZz2gSx2",
"objectId" : "-L_xNVcfZavjGFVv6iGs",
"timestamp" : 1552586771,
"type" : "pinion"
},
"pinions" : {
"Gmg1ojNoBiedFPRNSL4sBZz2gSx2" : {
"-L_xNVcfZavjGFVv6iGs" : {
"option A" : "Aaaa",
"option B" : "Cccc",
"question" : "Four",
"selectedId" : "FoFQDAGGX9hntBiBdXYCBHd8yas2",
"uid" : "Gmg1ojNoBiedFPRNSL4sBZz2gSx2"
},
"users" : {
"Gmg1ojNoBiedFPRNSL4sBZz2gSx2" : {
"email" : "eeee#gmail.com",
"fullname" : "Eeee",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2FGmg1ojNoBiedFPRNSL4sBZz2gSx2?alt=media&token=209e57ca-b914-4023-8f85-fadfae7b7407",
},
Would appreciate any help and let me know if you need any other information - thank you in advance :)
UPDATE:
It's working for the question and answers but I am getting an error "Unable to infer closure type in the current context" when calling the image:
#IBOutlet weak var senderProfileImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
showImageOfSender()
}
var ref = Database.database().reference()
var userId = "" //this was made equal to the autoId under pinion, under the users ID in another view controller
func showImageOfSender() {
var senderPhoto = [String]()
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let senderId = ref.child("pinions").child(uid).child(userId).child("uid")
ref.child("users").child(senderId).observeSingleEvent(of: .value, with: { snapshot in
//error is in the above line
let senderImage = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String
senderPhoto.append(senderImage)
let senderImageUrl = URL.init(string: senderImage)
self.senderProfileImage.sd_setImage(with: senderImageUrl)
})
}
I think this is what you mean, first import Firebase:
import Firebase
then get the database reference:
class PinionNotificationsViewController: UIViewController {
var ref: DatabaseReference!
...
}
then your function can look like this if you know the UID:
func showQuestionAndAnswers() {
let uid = userId
ref = ref.child("pinions").child(uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
let optionA = value?["option A"] as! String
let optionB = value?["option B"] as! String
print(optionA) // <- prints: "Bbbb"
print(optionB) // <- prints: "Dddd"
})
}
If you don't know the uid you can use
ref = ref.child("pinions")
ref.observe(.childAdded) { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
let optionA = value?["option A"] as! String
// then you can append these values into an array it will go through all of them eg:
self.answersArray.append(optionA) // answers array will contain all optionA values from all children in the database under `"pinions"`
}
This way in my experience would match the database order so in your array all options would be in the order of their children as they are in the database.
Hope this helps!

Swift child is returning Null when nested or ObserveSingleEvent, returns fine when not nested

I am trying to retrieve a child of a child. the entire snapshotValue returns null. When I retrieve the same data as a child (not nested) it retrieves fine.
I'm Using XCode 10 and Swift 4
To troubleshooting purposes, I have two nodes called 'Promoters'. One at the root and one nested inside a 'Partners' child (preferred). I will remove the top level node when I get the nested node working.
Here is the data structure:
"Partners" : {
"Acts" : [hidden],
"Promoters" : [ null, {
"Cell" : hidden,
"Contact Name" : “hidden”,
"Email" : “hidden”,
"Facebook" : “hidden“,
"Title" : "CHORD Productions"
} ]
},
"Promoters" : {
"chord" : {
"Title" : "Chord Productions"
}
}
This retrieves the data I'm looking for (a list of Titles to populate a picker):
let promotersDB = Database.database().reference().child("Promoters")
promotersDB.observe(.childAdded) { (snapshot) in
let snapshotValue = snapshot.value as! Dictionary<String, String>
let promoterName = snapshotValue["Title"]!
let promoter = PromoterClass()
promoter.promoterName = promoterName
self.promoterArray.append(promoter)
let isSuccess = true
completion(isSuccess)
}
This returns nil:
let promotersDB = Database.database().reference().child("Partners").child("Promoters")
promotersDB.observe(.childAdded) { (snapshot) in
let snapshotValue = snapshot.value as! Dictionary<String, String>
let promoterName = snapshotValue["Title"]!
let promoter = PromoterClass()
promoter.promoterName = promoterName
self.promoterArray.append(promoter)
let isSuccess = true
completion(isSuccess)
}
I'd prefer observeSingleEvent, but this also returns nil:
let promotersDB = Database.database().reference().child("Promoters")
promotersDB.observeSingleEvent(of: .value, with: { (snapshot) in
let snapshotValue = snapshot.value as! Dictionary<String, String>
let promoterName = snapshotValue["Title"]!
let promoter = PromoterClass()
promoter.promoterName = promoterName
self.promoterArray.append(promoter)
let isSuccess = true
completion(isSuccess)
})
The error is:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
**I am using force unwrapping for now to be reviewed at a later date after investigating how much of the data integrity can be done with backend rules :)
Any assistance would be greatly appreciated.
I think firebase usually suggests the Fan Out method when dealing with data trees, so you shouldn't nest array like "Promoters" anyways.
You'll also want to identify each of the Promoters by a uid instead of by their name (incase you have to change their name in the system).
So if you want, try to restructure your data like this:
let uid = Database.database().reference().child("Promoters").childByAutoId()
// uid will be some super long string of random letters and numbers, for example like: 1hjK2SCRV2fhCI0Vv3plGMct3mL2
"Promoters" : {
"1hjK2SCRV2fhCI0Vv3plGMct3mL2" : {
"Title" : "Chord Productions"
}
}
And then when you want to query values within that promoter's branch:
let titleRef = Database.database().reference().child("Promoters").child(uid)
titleRef.observeSingleEvent(of: .value) { (snapshot) in
if let dict = snapshot.value as? [String: AnyObject] {
let promoter = PromoterClass()
promoterName = dict["Title"] as? String
promoter.promoterName = promoterName
}
}

How to store data in form of object into firestore using swift

I want to store data into object form using swift language.The data structure of the data base is like
collection/
document/
collection/
document1/:
Invitess1(object) :
name :"santosh"
phone :1234567890
Invitee2(object) :
name :"sam"
phone:1234654768
.....
document 2/
Initee1(object) :
name:"red"
phone:4654343532
.......
is it possible to store data like this? if possible how to do it? i tried like this :
for var i in 0..<n { // n is no.of selected contacts
for var j in i...i {
print("amount is \(d[i])")
print("phone number is \(num[j])")
let dataToSave:[String: Any] = ["name" :"vijayasri",
"PhoneNumber":num[j],
"Amount": d[i],
]
}
}
var ref:DocumentReference? = nil
ref = self.db.collection("deyaPayUsers").document("nothing").collection("Split").addDocument(data: dataToSave){
error in
if let error = error {
print("error adding document:\(error.localizedDescription)")
} else {
print("Document ades with ID:\(ref!.documentID)" )
}
}
}
But it doesn't work. How to do it..
Your example code is never going to work as intended since dataToSave is overwritten every iteration of the j loop. Your inner j loop probably has a typo at i...i
To store multiple objects in one document, create the document in Swift with multiple objects in it. Since you know how to encode your object as [String:Any], just take those dictionaries combine into a larger [String:Any]document.
I would change your code to be more like:
var dataToSave: [String:Any] = []()
for var i in 0..<n { // n is no.of selected contacts
var inProcess: [String:Any] = []()
for var j in i...i {
print("amount is \(d[i])")
print("phone number is \(num[j])")
let detail: [String: Any] = ["name" :"vijayasri",
"PhoneNumber":num[j],
"Amount": d[i]]
inProcess["NextKey\(j)"] = detail
}
dataToSave["SomeKey\(i)"] = inProcess
}
var ref:DocumentReference? = nil
ref = self.db.collection("deyaPayUsers").document("nothing").collection("Split").addDocument(data: dataToSave){
error in
if let error = error {
print("error adding document:\(error.localizedDescription)")
} else {
print("Document ades with ID:\(ref!.documentID)" )
}
}
}

How to retrieve a value from dictionary in Swift 3

I have this function that fetch users from FireBase and convert them in Dictionary:
let leaderBoardDB = FIRDatabase.database().reference().child("scores1").queryOrderedByValue().queryLimited(toLast: 5)
leaderBoardDB.observe( .value, with: { (snapshot) in
print("scores scores", snapshot)
if let dictionary = snapshot.value as? [String: Any] {
for playa in dictionary {
let player = Player()
print("plaaaaayyyyyaaaaa", playa)
print("plaaaaayyyyyaaaaa key", playa.key)
print("plaaaaayyyyyaaaaa.value", playa.value)
player.id = playa.key
print(playa.key["name"])
}
}
}, withCancel: nil)
}
and I get this result:
plaaaaayyyyyaaaaa ("inovoID", {
name = Tatiana;
points = 6; }) plaaaaayyyyyaaaaa key inovoID plaaaaayyyyyaaaaa.value {
name = Tatiana;
points = 6; } aaaa i id Optional("inovoID")
the problem is that i can't obtain the name and the points of the user. when i try it with:
print(playa.key["name"])
it gaves me this error:
Cannot subscript a value of type 'String' with an index of type 'String'
can anyone help me with this, please?
Since your JSON is
"inovoID" : { "name" : "Tatiana", "points" : 6 }
playa.key is "inovoID"
playa.value is { "name" : "Tatiana", "points" : 6 }
The key is String and cannot be subscripted. That's what the error says.
You need to subscribe the value and safely cast the type to help the compiler.
if let person = playa.value as? [String:Any] {
print(person["name"] as! String)
}
I think you're looking for:
player.name = dictionary["name"] as? String
You don't need to iterate through the dictionary to access it's values. If you're looking for the value of a key, just get it.