firebase中的分页具有相同的子值

时间:2017-07-25 20:21:39

标签: ios swift firebase pagination

我的数据结构如下:

 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块中的引用在与上面的块相同的位置开始查询。任何帮助或建议将不胜感激。

我考虑过做一个扇子,并为汽车类型制作一个单独的结构。但这很难。

1 个答案:

答案 0 :(得分:2)

对于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

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