【问题标题】:How to read deeper into a snapshot Firebase Swift 3?如何更深入地阅读 Firebase Swift 3 快照?
【发布时间】:2023-03-27 14:48:02
【问题描述】:

使用当前的实现,我可以通过创建结构 FireBaseData 的实例来读取属于 var uid 的预订,该结构使用 Firebase 数据库中指定的值进行初始化。

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

Firebase 数据库结构:

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

根据@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()

@Jay 还建议在代码中对从 Firebase DB 检索到的对象数组进行排序,而不是使用 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
   })
    

【问题讨论】:

    标签: ios firebase swift3 firebase-realtime-database


    【解决方案1】:

    所以你在这之后是每个用户节点中的每个预订节点

    模板如下所示:

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

    【讨论】:

    • 根据 Firebase 文档,当使用 queryOrderedByChild 时,具有数值的子项按升序排序。在每个预订节点中,我将TimeStampDateAndTime 保存为负值,以便在从 Firebase 检索对象时以升序填充 tableView,因此 2017 年 1 月 10 日应该出现在 2016 年 9 月 26 日之前。不幸的是, queryOrderedByChild 对我的实现没有影响。请查看我更新的问题。
    • @bibscy 在您更新的问题中,您正在按 .value 读取预订(一次将它们全部读取),然后遍历它们以添加到数组中。最简单的解决方案是在读取数组后在代码中对数组进行排序 - 这将非常快,避免担心存储为负值。此外,与观察调用相比,Firebase 查询非常“繁重”,因此通过对代码进行排序,您可以完全消除查询!
    • 我已经用你的建议更新了我的问题,即对数组进行排序并且它可以工作。我不再将TimeStampDateAndTime 存储为负值。我正在阅读另一个 answer of yours,您在 cmets 区域中声明,当涉及大量数据时,使用 queryOrderedBy 从 Firebase 向应用程序提供排序数据比尝试读取数据并在代码中排序要快得多。您能否告诉我如何利用 Firebase 查询方法按升序排列预订?
    猜你喜欢
    • 2019-10-03
    • 2023-04-05
    • 2011-06-07
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 2017-03-26
    • 2012-09-29
    • 2022-08-06
    相关资源
    最近更新 更多