Tengo una colección, donde cada documento individual tiene una serie de referencias.
La estructura en Firestore es así:
collection1 doc1 doc2 doc3 name: string ... refs: Array collection2/x786123nd... collection2/z1237683s... ...Quiero convertir eso en:
[ {<doc1 as object>}, {<doc2 as object}, { name: "Document 3", refsResult: [ {<object here mapped from reference>}, {<object here mapped from reference>}, ] } ]Para resumir, desde firebase necesito obtener una salida de una lista de objetos donde cada objeto tiene una lista de objetos en lugar de referencias.
EL SIGUIENTE SNIPPET NO FUNCIONA
Estoy tratando de hacerlo a nivel de servicio en Angular usando RxJS para transformar la salida, algo como esto:
return this.afs.collection('collection1') .valueChanges() .pipe( switchMap(objects => from(objects).pipe( switchMap(obj => from(obj.refs).pipe( switchMap(ref => ref.get()), map(r => ({ ...obj, refsResult: r.data() })), tap(obj => console.log('OBJ', obj)), )), )), tap(objects => console.log(objects)) );Pero parece que solo recibo un objeto en lugar de una lista de objetos con 2. Además, parece que refsResult también es un objeto único en lugar de una matriz. Estoy seguro de que estoy usando mal los switchMaps, probablemente estén cancelando los otros resultados o algo similar.
Me gustaría mantener la solución dentro de la cadena de operadores rxjs.
EDIT 1 Lo hice funcionar de una manera pirateada, solo lo comparto aquí para brindar más contexto y ver si podemos encontrar una manera de hacerlo con RxJS.
return this.afs.collection('collection1') .valueChanges() .pipe( tap(objects => { objects.forEach(object => { object.refsResult = []; object.refs.forEach(ref => { ref.get().then(d => object.refsResult.push(d.data())); }) }) }), tap(programs => console.log(programs)) );El código anterior funciona pero no muy bien, ya que primero devuelve la colección y luego muta los objetos para inyectar los elementos dentro de la matriz. Espero que ayude
¡La ayuda es muy apreciada! :)
Puede usar combineLatest para crear un solo observable que emita una matriz de datos.
En tu caso, podemos usarlo dos veces de forma anidada:
El resultado es un solo observable que emite la colección completa de objetos, cada uno con su colección completa de datos de resultado de referencia. Entonces solo necesita un solo switchMap para manejar la suscripción a este único observable:
return this.afs.collection('collection1').valueChanges().pipe( switchMap(objects => combineLatest( objects.map(obj => combineLatest( obj.refs.map(ref => from(ref.get()).pipe(map(r => r.data()))) ).pipe( map(refsResult => ({ ...obj, refsResult })) ) )) )) );Para facilitar la lectura, probablemente crearía una función separada:
function appendRefData(obj) { return combineLatest( obj.refs.map(ref => ref.get().pipe(map(r => r.data()))) ).pipe( map(refsResult => ({ ...obj, refsResult })) ); } return this.afs.collection('collection1').valueChanges().pipe( switchMap(objects => combineLatest(objects.map(appendRefData))) );