firebase - 添加了新项目的 Firestore 实时分页
问题描述
我有一个聊天分页服务,可以接收 Firestore 集合中的旧项目。它的起点是 init 集合中的最新文档。但是我遇到的问题是在 init 之后向 observable 添加更新的项目,当服务开始分页时这些项目并不存在。
分页服务如下所示。
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)
操作员。问题在于它抓取了第一个订阅发出的最后一个项目。
那么,如果我使用向上分页,例如实时聊天服务的工作方式,我应该如何将实时数据添加到列表底部进行分页。
解决方案
推荐阅读
- gradle - Various files to various destination while RPM Generation using rpm plugin in gradle
- android - iOS/Android 上的泰语换行符
- javascript - Is it possible to add a certain javascript to a new html page in framework7?
- c - 为什么程序在操作系统中仍然有很多内存时内存不足?
- c - What happens to the child process after calling exec?
- css - CSS Grid Dynamically assign grid column or grid-template-columns
- django - 如何在 Django 2.0+ 中简单有效地创建相关对象?
- css - 如何在不改变纵横比和裁剪图像的情况下调整图像大小
- css - 动态 Angular 模板中文本子字符串的自定义样式
- regex - 如何获得完全匹配忽略正则表达式中的非数字?