[英]Firestore active document snapshot listener breaks sorting
我遇到了一個firestore問題,希望有人可以幫助我。
我有一個活動的文檔快照偵聽器,它似乎正在破壞排序行為,我不知道為什么。
在我的組件的構造函數中,我初始化了一次文檔快照偵聽器:
this.listen = this.fs.collection('users').doc('0EwcWqMVp9j0PtNXFDyO').ref.onSnapshot(t => {
console.log(t)
})
每當我單擊“排序”按鈕時,它都會初始化一個按名字排序的新集合查詢。
async onSort() {
if (this.first) {
this.first();
}
this.sort = this.sort === 'asc'? 'desc' : 'asc';
alert(this.sort)
let arr = []
let lastDoc = null
let queryRef = this.fs.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20);
this.users$ = this._users$.asObservable()
// initialize a blank list
this._users$.next([])
// subscribe to user list snapshot changes
const users1: { users: any, last: any } = await new Promise((resolve, reject) => {
this.first = queryRef.onSnapshot((doc) => {
console.log("Current data: ", doc);
const users = doc.docs.map(t => {
return {
id: t.id,
...t.data() as any
}
})
console.log(users)
resolve({
users: users,
last: doc.docs[doc.docs.length -1]
})
});
})
this._users$.next(this._users$.value.concat(users1.users))
}
但是,這並沒有按預期工作。 排序返回一條記錄(應該有 20 條記錄,基於限制)。
有趣的是,取消訂閱文檔快照會修復排序問題。 正在返回 20 條記錄,並且排序行為正確。
有人可以解釋我做錯了什么嗎?
這是重現該問題的最小 Stackblitz。
[編輯]
越來越接近解決方案和理解......感謝@ZackReam 的解釋以及@Robin 和@Zack 的規范答案。
似乎this._firestore.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20).onSnapshot(...)
確實發出了兩次 - 一次用於活動文檔偵聽器(在緩存中有 1 條記錄),第二次用於排序的集合(不在緩存中,因為每次執行sort
時switchMap
都會取消訂閱)。
我們可以在 Zack 發布的功能演示中看到這一點——它閃爍着與文檔偵聽器相對應的一條記錄,然后片刻之后,列表中填充了排序后的集合。
你的聽眾越活躍,結果的閃現就越奇怪。 這是設計使然嗎? 對我來說似乎有缺陷......
直觀地說,我希望this._firestore.firestore.collection('users').orderBy('firstName', this.sort as any).limit(20)
查詢中的snapshotChanges()
或valueChanges()
返回 20 個結果(排序后的前 20 個),獨立於任何其他文檔偵聽器。 這個查詢的第一個快照是來自文檔查詢的初始活動文檔,這與直覺相反——這應該與排序查詢無關。
我在一個簡化的環境中使用了您的示例數據,我想我知道發生了什么。 這是我的游樂場,只需更新AppModule
以指向您的 Firebase 項目。
當您調用onSort()
時,您正在重新訂閱queryRef.onSnapshot
。 此回調觸發兩次:
在 Playground 中,確保已訂閱Document ,然后訂閱Sorted Collection 。 在控制台中,您會看到它兩次觸發:
不幸的是,由於您將此偵聽器包裝在 Promise中,因此您只會獲得第一次火災,因此只能獲得緩存中的單個記錄。
似乎本地緩存是根據當前打開的onSnapshot
訂閱填充的。 因此,在您的情況下,您有一個偵聽器來監聽單個記錄的快照,因此這是您的緩存中唯一的東西。
在 Playground 中,嘗試使用各種訂閱狀態訪問Log Cache 。 例如,雖然只有
Document Subscribed
為 true,但緩存中只有一條記錄。 當兩個訂閱都處於活動狀態時,您會在緩存中看到大約 20 條記錄。如果您取消訂閱所有內容並點擊Log Cache ,則緩存為空。
事實證明,如果在上面的步驟 1 中沒有數據可以從緩存中返回,它會完全跳過該步驟。
在操場上,確保Document已取消訂閱,然后訂閱Sorted Collection 。 在控制台中,您會看到它只觸發一次:
這恰好適用於您的 Promise,因為第一次也是唯一一次觸發包含您希望的數據。
firebase-js-sdk
庫中的此評論按預期描述了此行為,以及原因。
Promise 與.onSnapshot
配對是擾亂數據流的主要因素,因為.onSnapshot
預計會觸發不止一次。 你可以改用.get
,它在技術上可以工作。
然而,正如 Robin 指出的那樣,專注於利用@angular/fire
功能的更具反應性的 RxJS 方法)將 go 走很長的路。
我找不到您的代碼的問題,因為您達到了 firebase 配額。 對我來說,您的排序似乎有點過於復雜並引入了賽車問題。 我認為您可以通過使用 RxJS 來降低復雜性。 像這樣的東西會起作用: https://stackblitz.com/edit/angular-ivy-cwthvf?file=src/app/app.component.ts
我無法真正測試它,因為您達到了配額。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.