2016-12-18 66 views
2

在当前的实现中,我可以通过创建一个结构为FireBaseData的实例来读取属于var uid的预订,该实例使用Firebase数据库中指定的值进行初始化。如何更深入地阅读Firebase Swift 3的快照?

我需要获得所有用户在/Users节点下的所有预订,然后将它们分配给一个数组,以便我可以在UITableVIew中显示这些值。我不知道如何更深入地阅读快照。

火力地堡数据库结构:

Firebase Tree

// 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 = "[email protected]"; 
     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 = "[email protected]"; 
     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 = "[email protected]"; 
     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 = "[email protected]"; 
     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; 
    }; 
    }; 
}) 

更新应答根据@Jay建议

*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() 

bookings are not ordered in ascending order

@Jay还建议将代码中检索到的对象数组排序,而不是使用Firebase提供的queryOrdered(by:_)方法。 这是我如何排序和过滤数组。

 // 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 
    }) 

回答

3

所以你在这里后每个用户节点

中的每个节点预订的模板看起来像:

users 
    uid_0 
    booking_0 
    booking_amount: "12" 
    booking_1 
    booking_amount: "14" 

通过.value的读取在用户节点都阅读。

每个用户节点都有多个预订子节点,因此我们需要遍历这些子节点以获取其子值。

每个孩子的内部都是我们想要获得的关键值对,在本例中为booking_amount和值。

let usersRef = myRootRef.child(byAppendingPath: "users") 

usersRef?.observe(.value, with: { snapshot in 

    if (snapshot!.value is NSNull) { 
     print("not found") 
    } else { 

     for user_child in (snapshot?.children)! { //iterate over each user node child 
     //assign the user_child enumerator to a snapshot 
     let user_snap = user_child as! FDataSnapshot 

     for booking in user_snap.children { //now iterate over each booking 
      //booking is a enumerator so make it a snapshot    
      let bookingSnap = booking as! FDataSnapshot 
      let dict = bookingSnap.value as! [String: String] 
      let amount = dict["booking_amount"] 

      print(amount!) 
     }  
     } 
    } 
}) 
+0

根据Firebase文档,当使用'queryOrderedByChild'时,具有数字值的孩子按升序排序。在每个预订节点中,我将'TimeStampDateAndTime'保存为负值,以便在从Firebase检索对象时按升序填充tableView,因此2017年1月10日应显示在2016年9月26日之前。不幸的是, 'queryOrderedByChild'在我的实现中没有效果。请看我更新的问题。 – bibscy

+0

@bibscy在您更新的问题中,您正在阅读.value(它一次读取所有内容)的预订,然后遍历它们以添加到数组中。最简单的解决方案是在读入代码后对数组进行排序 - 这将会超快,避免担心存储为负值。此外,与观察呼叫相比,Firebase查询非常“沉重”,因此通过在代码中进行排序,您可以完全消除查询! – Jay

+0

我已经用您的建议更新了我的问题,即将数组排序并运行。我不再将'TimeStampDateAndTime'存储为负值。我正在阅读另一个[你的答案](http://stackoverflow.com/questions/36589452),你在评论区域声明,当涉及大量数据时,使用'queryOrderedBy'从Firebase向应用程序提供分类数据是一个比尝试读取数据和按代码排序要快得多。您能否告诉我如何通过利用Firebase查询方法以升序排列预订? – bibscy