【问题标题】:Pagination in firebase with identical child values具有相同子值的firebase中的分页
【发布时间】:2017-12-31 22:34:48
【问题描述】:

我的数据结构如下:

 users: 
  user1:
   -carModel: evo x
   -username: importguy
   -region: north east 
  user2: 
   -carModel: evo x
   -username: evoguy
   -region: north east 
  user3: 
   -carModel: mustang gt
   -username: muscleguy
   -region: south east 

我希望用户能够搜索汽车,例如 evo,并显示拥有这些特定汽车的用户的结果。我需要为我的应用对这些结果进行分页。问题是我不知道如何正确查询这个。这是我到目前为止所拥有的。

  func fetchUsersBy(car: String) {

    if self.carCurrentKey == nil {

        let ref = USER_REF.queryOrdered(byChild: "carModel").queryStarting(atValue: car).queryLimited(toFirst: 3)

        ref.observeSingleEvent(of: .value, with: { (snapshot) in

            guard let snap = snapshot.children.allObjects as? [FIRDataSnapshot] else { return }
            guard let last = snapshot.children.allObjects.last as? FIRDataSnapshot else { return }

            snap.forEach({ (snapshot) in

                guard let userDict = snapshot.value as? Dictionary<String, AnyObject> else { return }
                guard let carModel = userDict["carModel"] as? String else { return }

                if carModel.contains(car) {
                    print(snapshot)
                }
            })
            self.carCurrentKey = last.key
            self.carCurrentValue = last.childSnapshot(forPath: "carModel").value as? String
        })
    } else {
       // where to start next query? 
       let ref = USER_REF.queryOrder(byChild: "carModel").queryStarting(atValue: self.carCurrentValue)
    }
}

我必须按 carModel 排序查询,以便在快照中将具有该特定汽车类型的所有用户分组在一起。由于所有汽车型号的值都相同,因此我无法确定从哪里开始或结束下一个分页查询。使用我在 else 块中的引用在与上面的块相同的位置启动查询。任何帮助或建议将不胜感激。

我考虑过进行扇出,并为汽车类型制作单独的结构。不过这会很困难。

【问题讨论】:

    标签: ios swift firebase pagination


    【解决方案1】:

    对于 startAt() 和 endAt(),您可以传递第二个值 childKey,如 here 所示。

    所以您的查询将如下所示:

    let ref = USER_REF.queryOrdered(byChild: "carModel").queryStarting(atValue: self.carCurrentValue, childKey: self.carCurrentKey).queryLimited(toFirst: 3+1)
    

    请注意,我使用了toFirst: 3+1。那是因为,令人讨厌的是, startAt() 是包容性的,没有办法跳过第一条记录。因此,由于我们是从上一页检索到的最后一条记录开始的,因此您需要查询一条额外的记录并丢弃第一个结果。

    这里有一个更完整的 JavaScript 示例。不够熟悉,无法将其翻译成 Swift,但它应该会为您提供完整的算法。

    class Cursor {
       constructor(baseRef, pageSize) {
          this.baseRef = baseRef;
          this.lastKey = null;
          this.lastValue = null;
          this.pageSize = pageSize;
       }
    
       next() {
         let ref = this.baseRef;
    
         if( this.lastValue !== null ) {
            // a previous page has been loaded so get the next one using the previous value/key
            // we have to start from the current cursor so add one to page size
            ref = ref.startAt(this.lastValue, this.lastKey).limitToFirst(this.pageSize+1);
         }
         else {
            // this is the first page
            ref = ref.limitToFirst(this.pageSize);
         }
    
         return ref.once('value').then(snap => {
           const keys = [];
           const data = []; // store data in array so it's ordered
    
           snap.forEach(ss => {
              data.push(ss.val());
              keys.push(ss.key);
           });
    
           if( this.lastValue !== null ) {
             // skip the first value, which is actually the cursor
             keys.shift();
             data.shift();
           }
    
           // store the last loaded record
           if( data.length ) {
             const last = data.length - 1;
             this.lastKey = keys[last];
             this.lastValue = data[last].author;
           }
    
           return data;
         });
       }
    }
    

    还有here's a working fiddle

    请记住,这是一个实时数据流。所以分页很棘手。通常,无限滚动比尝试在移动的数据集上保持真实的光标更容易(记录可以在数据更改、被删除、在中间添加等时重新排序)。

    【讨论】:

    • 看起来可行,但无论如何您可以在 swift 中发布解决方案吗?
    • 答案是在调用 startAt() 时使用 childKey。其余的只是帮助您了解下一步将走向何方的奖励。
    猜你喜欢
    • 2014-06-21
    • 2019-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多