Sto lavorando con Observables qui e AngularFire wrapper ma ecco come sono riuscito a farlo.
È un po 'folle, sto ancora imparando a conoscere gli osservabili e forse ho esagerato. Ma è stato un bell'esercizio.
Qualche spiegazione (non un esperto RxJS):
- songId $ è un osservabile che emetterà ID
- dance $ è un osservabile che legge quell'id e quindi ottiene solo il primo valore.
- quindi interroga il collectionGroup di tutti i brani per trovarne tutte le istanze.
- In base alle istanze che attraversa fino al genitore Dances e ottiene i loro ID.
- Ora che abbiamo tutti gli ID Dance, dobbiamo interrogarli per ottenere i loro dati. Ma volevo che funzionasse bene, quindi invece di interrogarli uno per uno li ho raggruppati in bucket da 10 (l'angolazione massima richiederà per una
in
query.
- Finiamo con N bucket e dobbiamo eseguire N query su Firestore per ottenere i loro valori.
- una volta che abbiamo eseguito le query su Firestore, dobbiamo ancora analizzare effettivamente i dati da quello.
- e finalmente possiamo unire tutti i risultati della query per ottenere un singolo array con tutte le danze in esso.
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();
Ho copiato il mio codice e ho cambiato i nomi delle variabili con i tuoi, non sono sicuro che ci siano errori, ma ha funzionato bene per me. Fammi sapere se trovi errori o puoi suggerire un modo migliore per testarlo con forse qualche finto firestore.