Firestore Live分页添加了新项目

时间:2018-07-11 17:53:54

标签: firebase pagination google-cloud-firestore

我有一个聊天分页服务,可以接收Firestore集合中的旧物品。它的起点是init集合中的最新文档。但是我遇到的问题是,在init之后向可观察对象添加了更新的项目,而当服务开始分页时却没有。

以下列出了分页服务。

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/scan';
import 'rxjs/add/operator/take';

// Options to reproduce firestore queries consistently
interface QueryConfig {
  path: string, // path to collection
  field: string, // field to orderBy
  limit?: number, // limit per query
  reverse?: boolean, // reverse order?
  prepend?: boolean // prepend to source?
}


@Injectable()
export class PaginationService {

  // Source data
  private _done = new BehaviorSubject(false);
  private _loading = new BehaviorSubject(false);
  private _data = new BehaviorSubject([]);

  private query: QueryConfig;

  // Observable data
  data: Observable<any>;
  done: Observable<boolean> = this._done.asObservable();
  loading: Observable<boolean> = this._loading.asObservable();


  constructor(private afs: AngularFirestore) { }

  // Initial query sets options and defines the Observable
  init(path, field, opts?) {
    this.query = { 
      path,
      field,
      limit: 2,
      reverse: false,
      prepend: false,
      ...opts
    }

    const first = this.afs.collection(this.query.path, ref => {
      return ref
              .orderBy(this.query.field, this.query.reverse ? 'desc' : 'asc')
              .limit(this.query.limit)
    })

    this.mapAndUpdate(first)

    // Create the observable array for consumption in components
    this.data = this._data.asObservable()
        .scan( (acc, val) => { 
          return this.query.prepend ? val.concat(acc) : acc.concat(val)
        })
  }


  // Retrieves additional data from firestore
  more() {
    const cursor = this.getCursor()

    const more = this.afs.collection(this.query.path, ref => {
      return ref
              .orderBy(this.query.field, this.query.reverse ? 'desc' : 'asc')
              .limit(this.query.limit)
              .startAfter(cursor)
    })
    this.mapAndUpdate(more)
  }


  // Determines the doc snapshot to paginate query 
  private getCursor() {
    const current = this._data.value
    if (current.length) {
      return this.query.prepend ? current[0].doc : current[current.length - 1].doc 
    }
    return null
  }


  // Maps the snapshot to usable format the updates source
  private mapAndUpdate(col: AngularFirestoreCollection<any>) {

    if (this._done.value || this._loading.value) { return };

    // loading
    this._loading.next(true)

    // Map snapshot with doc ref (needed for cursor)
    return col.snapshotChanges()
      .do(arr => {
        let values = arr.map(snap => {
          const data = snap.payload.doc.data()
          const doc = snap.payload.doc
          return { ...data, doc }
        })

        // If prepending, reverse array
        values = this.query.prepend ? values.reverse() : values

        // update source with new values, done loading
        this._data.next(values)
        this._loading.next(false)

        // no more values, mark done
        if (!values.length) {
          this._done.next(true)
        }
    })
    .take(1)
    .subscribe()

  }


  // Reset the page
  reset() {
    this._data.next([])
    this._done.next(false)
  }


}

如果我保持订阅有效(不使用.take(1),它将接收新项目,但随后将所有子预订添加到数据集的底部。因此,例如,如果我的初始数据集为

5、6、7、8、9、10、11 ...

然后添加一个新项目4

数据集现在变为5、6、7、8、9、10、11、4、5、6、7、8、9、10、11。

我的想法是创建一个单独的订阅,将新项目推送到数据集,但是具有limit(1)运算符。这样做的问题是,它捕获了第一个订阅发出的最后一个项目。

因此,如果我正在使用分页功能(例如实时聊天服务的工作方式),那么应该如何进行分页处理,并将实时数据添加到列表的底部。

0 个答案:

没有答案