With the current implementation I can read the bookings belonging to var uid
by creating an instance of a structure FireBaseData
which is initialized with the values specified in the Firebase Database.
I need to get all bookings for all users under /Users
node and then assign them to an array so that I can display the values in a UITableVIew. I don't know how to read deeper into the snapshot.
Firebase Database Structure:
// create a reference to Firebase
var dbRef:FIRDatabaseReference!
var uid = "lwrUjaDCcoOcx4K2gioO76JWp2i2"
// this array will hold all bookings for the logged in user
var bookingInfo = [FireBaseData]()
override func viewDidLoad() {
super.viewDidLoad()
dbRef = FIRDatabase.database().reference().child("Users")
startObservingDB() // observe the database for value changes
}
func startObservingDB() {
dbRef.child("lwrUjaDCcoOcx4K2gioO76JWp2i2").
observe(.value, with: { (snapshot: FIRDataSnapshot) in
// an instance of FireBaseData holding all bookings belonging to currentUid
var newBookingInfo = [FireBaseData]()
for booking in snapshot.children {
// after each iteration create an instance of FireBaseData with
// 'booking' for the current iteration & assign it to bookingItem
let bookingItem = FireBaseData(snapshot: booking as! FIRDataSnapshot)
// append the bookingItem after each iteration to newBookingInfo array
newBookingInfo.append(bookingItem)
}
//assign newBookingInfo to global variable bookingInfo so it can be used globally within the class
self.bookingInfo = newBookingInfo
}, withCancel: { (Error:Any) in
})
}
// use this struct to retrieve data from the snapshot received
struct FireBaseData {
var BookingAmount:String!
var BookingNumber:String!
.
.
... and so on
}
init(snapshot:FIRDataSnapshot){
if let BookingAmountContent = (snapshot.value! as? NSDictionary)?["BookingAmount"] as? String {
BookingAmount = BookingAmountContent
}
if let BookingNumberContent = (snapshot.value! as? NSDictionary)?["BookingNumber"] as? String {
BookingNumber = BookingNumberContent
.
.
.... and so on
}
snapshot.children_IS <FTransformedEnumerator: 0x60800023a380>
snapshot.value_IS({
lwrUjaDCcoOcx4K2gioO76JWp2i2 = {
718565122 = {
BookingAmount = 12;
BookingNumber = 718565122;
DateAndTime = "Mon, 26 Sep 2016 18:30";
EmailAddress = "1@gmail.com";
FlatNumber = 10;
FrequecyAmount = 48;
FrequencyName = Once;
FullName = "Michael ";
PhoneNumber = 25558882522;
PostCode = SE13TYY;
SelectedBathRow = 4;
SelectedBedRow = 3;
StreetAddress = "High Street";
SuppliesAmount = 5;
SuppliesName = "Bring cleaning supplies";
insideCabinets = 0;
insideFridge = 1;
insideOven = 0;
interiorWindows = 1;
laundryWash = 1;
};
890149009 = {
BookingAmount = 73;
BookingNumber = 890149009;
DateAndTime = "Sat, 01 Oct 2016 13:30";
EmailAddress = "1@gmail.com";
FlatNumber = 10;
FrequecyAmount = 48;
FrequencyName = Once;
FullName = "Michael ";
PhoneNumber = 25558882522;
PostCode = SE13TYY;
SelectedBathRow = 4;
SelectedBedRow = 3;
StreetAddress = "High Street";
SuppliesAmount = 5;
SuppliesName = "Bring cleaning supplies";
insideCabinets = 0;
insideFridge = 1;
insideOven = 0;
interiorWindows = 1;
laundryWash = 1;
};
};
xd5rwZzUqoRbfMp2rq5pTxuRB3s1 = {
116928124 = {
BookingAmount = 22;
BookingNumber = 116928124;
DateAndTime = "Fri, 16 Dec 2016 16:30";
EmailAddress = "b@gmail.com";
FlatNumber = 10;
FrequecyAmount = 22;
FrequencyName = "Every week";
FullName = Mi;
PhoneNumber = 28488824;
PostCode = RTRFHGT;
SelectedBathRow = 3;
SelectedBedRow = 1;
StreetAddress = "12 High St";
SuppliesAmount = 0;
SuppliesName = "I have cleaning supplies";
TimeStampBookingSavedInDB = 1481886718;
TimeStampDateAndTime = 1481905800;
insideCabinets = 0;
insideFridge = 0;
insideOven = 0;
interiorWindows = 0;
laundryWash = 0;
};
328241274 = {
BookingAmount = 22;
BookingNumber = 328241274;
DateAndTime = "Sun, 18 Dec 2016 16:30";
EmailAddress = "bi@gmail.com";
FlatNumber = 10;
FrequecyAmount = 22;
FrequencyName = "Every week";
FullName = Mi;
PhoneNumber = 28488824;
PostCode = RTRFHGT;
SelectedBathRow = 3;
SelectedBedRow = 1;
StreetAddress = "12 High St";
SuppliesAmount = 0;
SuppliesName = "I have cleaning supplies";
TimeStampBookingSavedInDB = 1481888650;
TimeStampDateAndTime = 1482078600;
insideCabinets = 0;
insideFridge = 0;
insideOven = 0;
interiorWindows = 0;
laundryWash = 0;
};
};
})
Updated Answer according to @Jay suggestion
*Problem : with this implementation `queryOrdered(byChild:)` has no effect.*
func startObservingDB() {
dbRef.queryOrdered(byChild: "TimeStampDateAndTime").observe(.value, with: { (snapshot: FIRDataSnapshot) in
// an instance of FireBaseData holding all bookings under currentUid
var newBookingInfo = [FireBaseData]()
//iterate over each user node child
for user_child in snapshot.children {
//user_snap is each user
let user_snap = user_child as! FIRDataSnapshot
//now iterate over each booking
for booking in user_snap.children {
// after each iteration through snapshot.children, create an instance of FireBaseData with 'booking' for the current iteration & assign it to bookingItem
let bookingItem = FireBaseData(snapshot: booking as! FIRDataSnapshot)
// append the bookingItem after each iteration to newBookingInfo array
newBookingInfo.append(bookingItem)
}
}
//assign newBookingInfo to global variable bookingInfo so it can be used globally within the class
self.bookingInfo = newBookingInfo
// reload the data every time FIRDataEventType is triggered by value changes in Database
self.tableView.reloadData()
}, withCancel: { (Error:Any) in
print("Huge (Error)")
})
//Set the estimatedRowHeight of your table view
tableView.estimatedRowHeight = 44.0
// Set the rowHeight of your table view to UITableViewAutomaticDimension
tableView.rowHeight = UITableViewAutomaticDimension
} // end of startObservingDB()
@Jay also suggested that to sort the array of objects retrieved from Firebase DB in code rather than using queryOrdered(by:_)
method provided by Firebase.
Here is how I am sorting and filtering the array.
// sort the array in place so that the most recent date will appear first
self.bookingInfo.sort(by: {(DateAndTimeObject_1,DateAndTimeObject2) -> Bool in
DateAndTimeObject_1.TimeStampDateAndTime < DateAndTimeObject2.TimeStampDateAndTime
})
// filter each element in the array against the condition specified in the body of the closure
self.bookingInfo = self.bookingInfo.filter({(firstElementInArray) -> Bool in
firstElementInArray.TimeStampDateAndTime == 1483201800
})
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…