How to unpack multiple levels of nested JSON in Firebase Database
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
Updating nested objects firebase
You can use multi-path updates.
var userRef = ref.child(hashedEmail);
var updateObject = {
name: 'Rohan Dalvi',
"externalLinks/website": 'mywebsite'
};
userRef.update(updateObject);
By using the "externalLinks/website"
syntax in the object literal it will treat the nested path as an update and not a set for the nested object. This keeps nested data from being deleted.
Get data out of array of Firebase snapshots
I am not sure if the question can be answered without knowing how the array is built. One gotcha is the For-in loops variable is a NSFastEnumerationIterator so it needs to be downcast to what kind of 'thing' you want it to be. You may have done that so this is just for future reference.
That being said, I crafted up some code and broke it down a bit - maybe it will point you in the right direction.
The code below reads in all nodes by .value and then iterates over the snapshot and stores each child in an array as a FDataSnapshot. Then the code iterates over that array and prints the 'guardian' from each snapshot stored in the array.
I also included your code to print the guardianID and it works as well so my guess is the problem lies with how the array is being initially populated or in this line
for snapshot in self.guardians
as the snapshot is a NSFastEnumerationIterator
let ref = self.myRootRef.child(byAppendingPath: "guardian_node")!
ref.observe(.value, with: { snapshot in
if ( snapshot!.value is NSNull ) {
print("not found")
} else {
var guardianArray = [FDataSnapshot]()
for child in snapshot!.children {
let snap = child as! FDataSnapshot //downcast
guardianArray.append(snap)
}
for child in guardianArray {
let dict = child.value as! NSDictionary
let thisGuardian = dict["guardian"]!
print(thisGuardian)
//your code
let guardianID = (child.value as? NSDictionary)?["guardian"] as? NSString
print(guardianID!)
}
}
})
*This is Swift 3 and Firebase 2.x but the concept is the same.
Get with Flutter a nested JSON from Firebase DataSnapshot
I was also looking on how to handle nested json objects in Flutter with Cloud Firestore and found your post. As I solved my problem, maybe it helps you too: In the "fromJson"-factory of my model I had to parse every element in the list with jsonEncode and jsonDecode before adding it to the model.
in the DatabaseService:
Future<LocationRecordings> getLocationRecordings(String location) async {
DocumentReference document = locationRecordingsCollection.document((location));
DocumentSnapshot documentSnapshot = await document.get();
var data = LocationRecordings.fromJson(documentSnapshot.data);
return data;
}
in the model:
factory LocationRecordings.fromJson(Map<String, dynamic> json) {
List<Recording> recList = [];
List<dynamic>.from(json['recordings']).forEach((content) {
Recording recording = Recording.fromJson(jsonDecode(jsonEncode(content)));
recList.add(recording);
});
return new LocationRecordings(recordings: recList, state: json['state']);
}
Swift Firebase -How to get all the k/v when using queryOrdered(byChild: ).queryEqual(toValue: )
The DataSnapshot
class has built-in methods to loop over its children.
reviewsRef?.observeSingleEvent(of: .value, with: { [weak self](snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot;
print(snap.key)
print(snap.value)
print(snap.childSnapshot(forPath: "buyerUID").value)
}
})
Also see other search results for looping over Firebase child nodes in Swift.
Query multiple keys on Firebase
I would suggest using a DispatchGroup
and mutual exclusion to handle asynchronous functions within a for loop. Here is the code you provided with a DispatchGroup
to ensure that all of the asynchronous functions in the loop have completed before it checks the if statement:
let myGroup = DispatchGroup()
var found = false
// iterate through your array
for key in albumKeys {
let album = database.child(self.albumsKey).child(key)
// lock the group
myGroup.enter()
album.observeSingleEventOfType(.Value, withBlock: { snapshot in
if current.name == "My Artwork" {
found = true
}
// after the async work has been completed, unlock the group
myGroup.leave()
})
}
// This block will be called after the final myGroup.leave() of the looped async functions complete
myGroup.notify(queue: .main) {
if !found {
completion(nil)
}
}
Anything contained in the myGroup.notify(queue: .main) {
codeblock will not execute until myGroup.enter()
and myGroup.leave()
have been called the same amount of times. Be sure to call myGroup.leave()
within the Firebase observe block (after the async work) and make sure that it is called even if an error is produced from the observe.
Related Topics
Empty Class in Swift Playground Gives _Lldb_Expr_ Error
Swift: How to Get Information for an Application Which Is Not Running
How to Retrieve Audio File from Parse Swift
Get Element from Array of Dictionaries According to Key
Exc Bad Access After Coding Signing
How to Convert This Date Format in Swift
How to Generate a Random Unicode Character in Swift
How to Use Dispatchgroup/Gcd to Execute Functions Sequentially in Swift
How to Find a Maximum Value in a Swift Dictionary
Tests for Custom Uitableviewcell, Cellforrowatindexpath Crashes with Nil Outlets
Update Firebase Multi-Location with Error: Path Is an Ancestor of Path. Swift
Swift: Casting a Floatingpoint Conforming Value to Double
Can Openssl Be Bundled for Wget Wrapper App to Reference in Xcode Project
Bulk Fix Hundreds of "#Selector Not Exposed to Objective-C" Errors in Xcode 9 or 9.1