Burada Observables ve AngularFire paketleyiciyle çalışıyorum ama işte bunu nasıl başardım.
Biraz çılgınca, hala gözlemlenebilirler hakkında bilgi alıyorum ve muhtemelen abarttım. Ama güzel bir egzersizdi.
Bazı açıklamalar (bir RxJS uzmanı değil):
- songId $, kimlikleri yayacak bir gözlemlenebilir
- dance $, bu kimliği okuyan ve sonra yalnızca ilk değeri alan bir gözlemlenebilirdir.
- daha sonra tüm örneklerini bulmak için tüm şarkıların collectionGroup'unu sorgular.
- Örneklere bağlı olarak, ana Danslara geçer ve kimliklerini alır.
- Artık verilerini almak için onları sorgulamamız gereken tüm Dans kimliklerine sahip olduğumuza göre. Ancak iyi performans göstermesini istedim, bu yüzden tek tek sorgulamak yerine onları 10'luk kovalar halinde topluyorum (bir
in
sorgu için maksimum açısal alan gerekir .
- N kova ile sonuçlanırız ve değerlerini almak için firestore'da N sorgu yapmamız gerekir.
- firestore'da sorguları yaptığımızda, yine de verileri gerçekten çözümlememiz gerekir.
- ve son olarak, içindeki tüm Dansları içeren tek bir dizi elde etmek için tüm sorgu sonuçlarını birleştirebiliriz.
type Song = {id: string, name: string};
type Dance = {id: string, name: string, songs: Song[]};
const songId$: Observable<Song> = new Observable();
const dance$ = songId$.pipe(
take(1), // Only take 1 song name
switchMap( v =>
// Query across collectionGroup to get all instances.
this.db.collectionGroup('songs', ref =>
ref.where('id', '==', v.id)).get()
),
switchMap( v => {
// map the Song to the parent Dance, return the Dance ids
const obs: string[] = [];
v.docs.forEach(docRef => {
// We invoke parent twice to go from doc->collection->doc
obs.push(docRef.ref.parent.parent.id);
});
// Because we return an array here this one emit becomes N
return obs;
}),
// Firebase IN support up to 10 values so we partition the data to query the Dances
bufferCount(10),
mergeMap( v => { // query every partition in parallel
return this.db.collection('dances', ref => {
return ref.where( firebase.firestore.FieldPath.documentId(), 'in', v);
}).get();
}),
switchMap( v => {
// Almost there now just need to extract the data from the QuerySnapshots
const obs: Dance[] = [];
v.docs.forEach(docRef => {
obs.push({
...docRef.data(),
id: docRef.id
} as Dance);
});
return of(obs);
}),
// And finally we reduce the docs fetched into a single array.
reduce((acc, value) => acc.concat(value), []),
);
const parentDances = await dance$.toPromise();
Kodumu kopyaladım ve değişken adlarını sizinkiyle değiştirdim, herhangi bir hata olup olmadığından emin değilim, ancak benim için iyi çalıştı. Herhangi bir hata bulursanız bize bildirin veya belki sahte bir yangın deposu ile test etmenin daha iyi bir yolunu önerebilirsiniz.