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

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

Source Tutorial Link

AngularFire2 used for FireStore database operations

enter image description here

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