Swift - Firebase Error, How to Access to First Child - swift

I'm using firebase now and I got stuck with this.
I have a contactList like below.
I want to get the keys (like "-L8per5UdCjQyCBxs5Oo" for the one) but I don't know how to do this.
I tried something like this:
guard let contactList = self.user?.contactList else { return }
print(contactList[0])
And the error message is this.
Cannot subscript a value of type '[String : [String : String]]' with an index of type 'Int'
How can I fix this problem?
Thank you.

var ref:DatabaseReference?
var contactListArray:[DataSnapshot] = [] //you could create an array to save your children
func startListening() {
ref = Database.database().reference().child("contactList")
ref?.observe(.childAdded) {(snapshot) in
self.contactListArray.append(snapshot) // doing this, you can access the first child by contactListArray[0]
// This is how to access info in your snapshot if you need it
let key = snapshot.key //HERE: you'll get the keys
let props = snapshot.value as! Dictionary<String, AnyObject>
let userId = props["userId"] //HERE: how to access to data
}
}

You could iterate through fetched objects via:
for (key, value) in contactList {
///
}
If you want to get the first object, you can write:
contactList.first

Related

updateChildValues() does not work, but setValue() does

I'm trying to implement fan out and here is the problem: When I'm trying to updateChildValues in my usersOrdersRef reference, it just does nothing. I expect it to create the user_orders node, and child node with my userid and put a value there.
If I use setValues instead, it works fine, but I need to add values without deleting all previous data. What am I doing wrong?
Code:
for item in orderArray {
let childRef = ref.child(item.date!)
//this works fine
childRef.updateChildValues(item.convertToDictionary() as! [AnyHashable : Any]) { [unowned self] (error, reference) in
if error != nil {
print(String(describing: error?.localizedDescription))
}
let usersOrdersRef = Database.database().reference().child("users-orders").child(self.appUser.uid)
var primary = false
if (item.precursor == "") { primary = true }
//this does not work, but if i use "setValue" instead it will store data
usersOrdersRef.updateChildValues([item.date : primary])
}
}
Your problem:
//this does not work, but if i use "setValue" instead it will store data
usersOrdersRef.updateChildValues([item.date : primary])
I found myself in the same situation.
The problem was the data type of the key. When I casted the key to a String it started to function.
Hope this helps someone in the same situation.
I have the same problem
If I use
let newHashTagRef = Api.HashTag.REF_HASHTAG.child(word.lowercased())
newHashTagRef.updateChildValues([newPostId: true])
=> not working
when I replace
let newHashTagRef = Api.HashTag.REF_HASHTAG.child(word.lowercased())
newHashTagRef.setValues([newPostId: true])
=> it works but it will delete all previous data
Solution
let newHashTagRef =
Api.HashTag.REF_HASHTAG.child(word.lowercased()).child(newPostId)
newHashTagRef.setValue(true)
I resolve it by myself , now it works like this
let usersOrdersRef = Database.database().reference().child("users-orders").child(self.appUser.uid).child(item.date!)
var primary = false
if (item.precursor == "") { primary = true }
usersOrdersRef.setValue(primary)
In that case setValue does not delete all previous data, just adds new
You just need to cast your optional data key into the updateChildValues function.
Updated Code:
for item in orderArray {
let childRef = ref.child(item.date!)
//this works fine
childRef.updateChildValues(item.convertToDictionary() as! [AnyHashable : Any]) { [unowned self] (error, reference) in
if error != nil {
print(String(describing: error?.localizedDescription))
}
let usersOrdersRef = Database.database().reference().child("users-orders").child(self.appUser.uid)
var primary = false
if (item.precursor == "") { primary = true }
// this will work now, as we have explicity cast the key
usersOrdersRef.updateChildValues([item.date! : primary])
}
}

How to retrieve the value of the key changed in a child in firebase realtime database using observe

i was trying to write a code to pull a data from the realtime database using observe for child changed. But i don't know what the mistake is but the code fails. From my debugging study, i found that the observe was successfully triggered when the value changed, but it fails when i try to get the snapshot value to a variable. How should data be retrieved in a observe for child change case.
func userBalance() {
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
print("Snapshot: ", snapshot)
print("Snapshot Value", snapshot.value)
guard let data = snapshot.value as? NSDictionary else {
print("checkpoint fail test")
return
}
guard let userBalance = data[Constants.BALANCE] as? String else { return }
// update UserDefaults
userDefault.setString(userBalance, forKey: "userBalance")
//update local session
UserDataHandler.Instance.balance = userBalance
}) }
kindly help me out, thanks in advance.
Debugging Data :
Snapshot: Snap (balance) 100
Snapshot Value Optional(100)
checkpoint fail test
Thanks guys, i found the answer, may be it will help someone else. I am put down the new code that worked.
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
guard let key = snapshot.key as? String else { return }
guard let value = snapshot.value as? String else { return }
if key == Constants.BALANCE {
guard let userBalance = value as? String else { return }
// update UserDefaults
userDefault.setString(userBalance, forKey: "userBalance")
//update local session
UserDataHandler.Instance.balance = userBalance
}
}) }
The problem was that the observe detects the change in the database as one by one, so the snapshot comes as a single data for every change, if you change multiple values in a go, the observe detects it as multiple changes, one by one with each change as change of one value. So when i changed it to direct string it worked. You were right #Achref Gassoumi the problem was with the cast. Just after you told about it, i tried it out. Thanks.
I think your problem probably is with the cast
try the following :
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
guard let data = snapshot.value as? [<String,anyObject>] else {
print("checkpoint fail test")
return
}
print (data)

Swift Firebase access data inside child snapshot (by childAdded)

I posted a question previously regarding how to access data inside a child snapshot, where I got a very well-working answer. However, this solution only allowed me to retrieve the data by value - and not my child. You see, I had a JSON tree-structure like this:
Players {
PlayerID {
Username
Rank
Achievements {
Rookie: yes
}
}
And then I realized that I really need multiple 'childByAutoId' under the 'Achievements' - that will look something like this:
Player {
PlayerID {
Username
Rank
Achievements {
autoID1 {
isAchieved: yes
}
autoID2 {
isAchieved: yes
}
}
}
So how would I go on trying to grab the very ChildValues of each childByAutoId? I know for a fact that this works with the 'ChildAdded' on observe Snapshot, however - this doesn't seem to be a feature here.
Here is the code I have right now:
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
if let achieveMedal = achievementDictionary["Rookie"] as? String {
print(achieveMedal)
}
}
}
Help would be greatly appreciated!
How about a JSON tree structure like this:-
Achievements : {
achievement1 : true,
achievement2 : true,
achievement3 : false,
achievement4 : true,
}
For retrieving your achievements:-
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
for each in achievementDictionary{
print(each.0) // achievement name
print(each.1) // isAchieved (true/false)
}
}
}
}
It's not advisable to add such deep nodes in your DB for navigation reason's .
But this code will also work for the childByAutoID case, i.e each.0 will be your autoID AND each.1 will become that id's corresponding dictionary.For deeper details of that dictionary just navigate through the dictionary

How to delete from Firebase database

Hi i have followed this tutorial: https://www.youtube.com/watch?v=XIQsQ2injLo
This explains how to save and retrieve from the database, but not how to delete. I am wondering how to delete the database node that belongs to the cell that is being deleted. Thanks
Edit. Code updated for Swift 3 and Swift 4.
I'm always using the remove with completion handler:
static let ref = Database.database().reference()
static func remove(child: String) {
let ref = self.ref.child(child)
ref.removeValue { error, _ in
print(error)
}
}
So for example if I want to delete the following value:
I call my function: remove(child: "mixcloudLinks")
If I want to go deeper and delete for example "added":
I need to change the function a little bit.
static func remove(parentA: String, parentB: String, child: String) {
self.ref.child("mixcloudLinks").child(parentA).child(parentB).child(child)
ref.removeValue { error, _ in
print(error)
}
}
Called like:
let parentA = "DDD30E1E-8478-AA4E-FF79-1A2371B70700"
let parentB = "-KSCRJGNPZrTYpjpZIRC"
let child = "added"
remove(parentA: parentA, parentB: parentB, child: child)
This would delete just the key/value "added"
EDIT
In case of autoID, you need to save the autoID into your Dictionary to be able to use it later.
This is for example one of my functions:
func store(item: MyClassObject) {
var item = item.toJson()
let ref = self.ref.child("MyParentFolder").childByAutoId()
item["uuid"] = ref.key // here I'm saving the autoID key into the dictionary to be able to delete this item later
ref.setValue(item) { error, _ in
if let error = error {
print(error)
}
}
}
Because then I'm having the autoID as part of my dictionary and am able to delete it later:
Then I can use it like .child(MyClassObject.uuid).remove... which is then the automatic generated id.
we can store the randomly generated id as the user id in the database and retrieve that to delete
for e.g. :
let key = ref?.childByAutoId().key
let post = ["uid": key,
"name": myName,
"task": myTask]
ref?.child(key!).setValue(post)
in order to delete
setvalue of the id as nil
for e.g. :
var key = [string]()
ref?.child(key[indexPath.row]).setValue(nil)
key.remove(at: indexPath.row)
myArray.remove(at: indexPath.row)
myTable.reloadData()

SwiftyJSON Property Trouble

I am working with SwiftyJSON which is great. I am however having an issue with storing the JSON(data:) result in a property in my viewController. The standard use of SwiftyJSON works fine.
let json = JSON(data: data)
let name = json[1]["name"].string
My problem occurs when I try to create a property to store the result of JSON(data:)
// Property
var jsonData : JSON?
someMethod()
{
let json = JSON(data: data)
self.jsonData = json
if let name = self.jsonData[1]["name"].string
{
print(name)
}
}
When I do this I get an error on the following line.
if let name = self.jsonData[1]["name"].string
Cannot find member 'string'
Does anyone know why this is?
You are using an optional property.
var jsonData : JSON?
just use
if let name = self.jsonData?[1]["name"].string
in place of
if let name = self.jsonData[1]["name"].string
in your case complier trying to find a property which can be a nil.