简体   繁体   English

Firestore + AngularFire2分页(按范围查询项目 - .startAfter(lastVisible))

[英]Firestore + AngularFire2 pagination ( query items by range - .startAfter(lastVisible) )

In a component I want to pull a range of items from FireStore, for ex. 在一个组件中,我想从FireStore中提取一系列项目,例如。 from 0 to 5, from 5 to 10 etc. I found this in FireStore's docs, but they dont use AngularFire2 so as harder I tried to refactor as bigger mess I got. 从0到5,从5到10等我在FireStore的文档中发现了这一点 ,但他们不使用AngularFire2,因此我更难以重构为更大的混乱。 I made it working by simply splice() 'ing: 我通过简单的splice()来实现它:

service ->

topFirstScores(): AngularFirestoreCollection<Score> {
  return this.fireRef.collection('scores', r => r
          .orderBy('score', 'desc').limit(6)
  );
}

component ->

$scores = new Subject();

this.scores$ = this.$scores.asObservable();
if (this.scores === 'first') {
  this.scoreS.topFirstScores().valueChanges().take(1)
    .subscribe(_ => this.$scores.next(_.splice(0, 3)))
} else {
  this.scoreS.topFirstScores().valueChanges().take(1)
    .subscribe(_ => this.$scores.next(_.splice(3, 3)))
}

But this seems more as a workaround. 但这似乎更像是一种解决方法。 Could anyone translate this: 谁能翻译这个:

var first = db.collection("cities")
        .orderBy("population")
        .limit(25);

return first.get().then(function (documentSnapshots) {
  // Get the last visible document
  var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
  console.log("last", lastVisible);

  // Construct a new query starting at this document,
  // get the next 25 cities.
  var next = db.collection("cities")
          .orderBy("population")
          .startAfter(lastVisible)
          .limit(25);
});

That preferably returns AngularFirestoreCollection<T> ? 那最好返回AngularFirestoreCollection<T>

I had the same Problem and this is what i did. 我有同样的问题,这就是我做的。

Service 服务

private _data: BehaviorSubject<Scores[]>;
public data: Observable<Scores[]>;
latestEntry: any;

constructor(private afs: AngularFirestore) {}

// You need to return the doc to get the current cursor.
  getCollection(ref, queryFn?): Observable<any[]> {
    return this.afs.collection(ref, queryFn).snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data();
        const id = a.payload.doc.id;
        const doc = a.payload.doc;
        return { id, ...data, doc };
      });
    });
  }
// In your first query you subscribe to the collection and save the latest entry
 first() {
  this._data = new BehaviorSubject([]);
  this.data = this._data.asObservable();

  const scoresRef = this.getCollection('scores', ref => ref
    .orderBy('score', 'desc')
    .limit(6))
    .subscribe(data => {
      this.latestEntry = data[data.length - 1].doc;
      this._data.next(data);
    });
  }

  next() {
    const scoresRef = this.getCollection('scores', ref => ref
      .orderBy('scores', 'desc')
       // Now you can use the latestEntry to query with startAfter
      .startAfter(this.latestEntry)
      .limit(6))
      .subscribe(data => {
        if (data.length) {
          // And save it again for more queries
          this.latestEntry = data[data.length - 1].doc;
          this._data.next(data);
        }
      });
  }

Component 零件

  scores$: Observable<Scores[]>;
  ...
  ngOnInit() {
    this.yourService.first();
    this.scores$ = this.yourService.data;
  }

  nextPage() {
   this.yourService.next();
  }

I don't know about FireBase, but I'am awesome when you ask about all the items and then filtered. 我不知道FireBase,但是当你询问所有项目然后过滤时我真棒。

If you make a method that has as arguments, page and size and an array lastScore I supouse that you can make some like (NOTE: I have NOT Firestone and, the most probably, I'm wrong and the code is bad) 如果你创建一个方法,包括参数,页面和大小以及一个数组lastScore I supouse,你可以做一些(注意:我没有Firestone,最可能的,我错了,代码很糟糕)

//In service

lastScores:number[]=[];
lastPage:number=0; //use to know where you reach the last page
getNextHightScores(page:number,count:number)
{
    //get the limit
    let last=page>0?lastScores[page-1]:999999999   //if page=0 a bigger score
    //use where and limit
    return afs.collection<Item>('scores', r =>  
            r.where("score", "<", last).orderBy("score","desc").limit(count)
            .valueChanges()
            .do(r=>{  //using do to store the lastScore
               if (r.length)
                   this.lastScore[page]=r[r.length-1].score;
               if (r.length<count)
                   this.lastPage=page;
            })
}

//in component
page:number=0;
ngOnInit(){
    getValues(0);
}

getValues(page)
{
    service.getNextHightScore(page,5).subscribe(r=>{console.log(r)})
}
//and 
<button (click)="page=page+1;getValues(page)">next scores</button>

Source Tutorial Link 源教程链接

AngularFire2 used for FireStore database operations AngularFire2用于FireStore数据库操作

在此输入图像描述

using below methods: 使用以下方法:

For Next Page 对于下一页

    nextPage() {
      this.disable_next = true;
      this.firestore.collection('People', ref => ref
        .limit(5)
        .orderBy('timestamp', 'desc')
        .startAfter(this.lastInResponse)
      ).get()
        .subscribe(response => {

          if (!response.docs.length) {
            this.disable_next = true;
            return;
          }

          this.firstInResponse = response.docs[0];

          this.lastInResponse = response.docs[response.docs.length - 1];
          this.tableData = [];
          for (let item of response.docs) {
            this.tableData.push(item.data());
          }

          this.pagination_clicked_count++;

          this.push_prev_startAt(this.firstInResponse);

          this.disable_next = false;
        }, error => {
          this.disable_next = false;
        });
    }

For Previous Page 对于上一页

    prevPage() {
      this.disable_prev = true;
      this.firestore.collection('People', ref => ref
        .orderBy('timestamp', 'desc')
        .startAt(this.get_prev_startAt())
        .endBefore(this.firstInResponse)
        .limit(5)
      ).get()
        .subscribe(response => {
          this.firstInResponse = response.docs[0];
          this.lastInResponse = response.docs[response.docs.length - 1];

          this.tableData = [];
          for (let item of response.docs) {
            this.tableData.push(item.data());
          }

          //Maintaing page no.
          this.pagination_clicked_count--;

          //Pop not required value in array
          this.pop_prev_startAt(this.firstInResponse);

          //Enable buttons again
          this.disable_prev = false;
          this.disable_next = false;
        }, error => {
          this.disable_prev = false;
        });
    }

Check complete tutorial and demo on this link 查看此链接上的完整教程和演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM