Retrieve a collection within AngularFire that includes a subquery

I have the following function

getParticipations(
    meetingId: string
  ): Observable<Participation[]> {
    return this.meetingCollection
      .doc(meetingId)
      .collection<ParticipationDto>('participations')
      .snapshotChanges()
      .pipe(
        map(actions =>
          actions.map(m => {
            const participationDto = m.payload.doc.data() as ParticipationDto;
            const id = m.payload.doc.id;
            return new Participation(id, participationDto.vart, null);
          })
        )
      );
  }

In the participationDto, there is a document reference that I need to retrieve in order to return an object (participation) with a mapping of the referenced document.

Here's an update to the code:

  getParticipations(
    meetingId: string
  ): Observable<Participation[]> {
    return this.meetingCollection
      .doc(meetingId)
      .collection<ParticipationDto>('participations')
      .snapshotChanges()
      .pipe(
        mergeMap(actions =>
          forkJoin(
            actions.map(m => {
              const participationDto = m.payload.doc.data() as ParticipationDto;
              const id = m.payload.doc.id;
              return this.participantCollection.doc(participationDto.participant.id).get().pipe(
                map(pp => {
                  return new Participation(id, participationDto.vart, pp.data() as Participant);
                })
              );
            })
          )
        )
      );
  }

This updated code resolves the issue where it was returning an

Observable<Observable<Participation>[]>
. By using mergeMap and forkJoin, the Observables are merged correctly while keeping the
Observable<Participation[]>
format.

I hope this helps!

Answer №1

If you're looking to optimize your code, consider implementing forkJoin for the inner list of Observables and transitioning the outer map function to a switchMap in this scenario.

     fetchUserResponses(
    meetingKey: string
  ): Observable<Response[]> {
    return this.meetingRepository
      .retrieveDocument(meetingKey)
      .gatherCollection<ResponseData>('responses')
      .watchChanges()
      .pipe(
        switchMap(actions =>
          forkJoin(actions.map(response => {
            const responseData = response.payload.doc.data() as ResponseData;
            const identifier = response.payload.doc.id;
            return this.userCollection.retrieveDocument(responseData.userId).fetch().pipe(
              map(u => {
                return new Response(identifier, responseData.type, u.data() as User);
              })
            ));
          })
        )
      );
  }

Answer №2

To achieve the desired outcome, it is recommended to utilize mergeMap in place of map

An example implementation is shown below

getParticipations(
    meetingId: string
  ): Observable<Participation[]> {
    return this.meetingCollection
      .doc(meetingId)
      .collection<ParticipationDto>('participations')
      .snapshotChanges()
      .pipe(
        mergeMap(actions =>
          actions.map(m => {
            const participationDto = m.payload.doc.data() as ParticipationDto;
            const id = m.payload.doc.id;
            return this.participantCollection.doc(participationDto.participant.id).get().pipe(
              map(pp => {
                return new Participation(id, participationDto.vart, pp.data() as Participant);
              })
            );
          })
        )
      );
  }


getParticipations(
    meetingId: string
  ): Observable<Participation[]> {
    return this.meetingCollection
      .doc(meetingId)
      .collection<ParticipationDto>('participations')
      .snapshotChanges()
      .pipe(
        map(actions =>
          actions.map(m => {
            const participationDto = m.payload.doc.data() as ParticipationDto;
            const id = m.payload.doc.id;
            return this.participantCollection.doc(participationDto.participant.id).get().pipe(
              mergeMap(pp => {
                return new Participation(id, participationDto.vart, pp.data() as Participant);
              })
            );
          })
        )
      );
  }

(As this solution involves nested structures and complexities, and no stackblitz has been provided for validation, please notify me if any issues arise so I can remove this answer)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 6 - Defining two components with several modules nested within each other

There are two components, C1 and C2. Each component has its own module file. How can I declare C1 in C2 in Angular 6? // Module 1 @NgModule({ imports: [], exports: [], declarations: [ ComponentX, ComponentY ], providers: [] }) // Module 2 @NgModule ...

Warning: Obsolescence of Typescript Detected

Having an issue with my login code in TypeScript. The 'subscribe' function is deprecated and I'm not sure how to proceed. Can anyone provide some guidance? doLogin() { this.userService.doLogin(this.loginForm.value).subscribe( r ...

Creating interactive features for a TypeScript interface

I was looking to create a dynamic interface with custom properties, like so: data: dataInterface []; this.data = [ { label: { text: 'something', additionalInfo: 'something' } }, { bar: { text: ' ...

Issue regarding custom CSS implementation in Angular project

Being a French speaker, I apologize in advance for any mistakes I might make. I am also fairly new to Angular, so if you could provide detailed explanations in your responses, it would be greatly appreciated. Thank you. I am trying to import a custom CSS ...

Unable to use 'ngFor' as it is not recognized as a property of ... in a mixed AngularJS and Angular environment

My AngularJS and Angular hybrid application is giving me trouble when I try to downgrade my Angular test.component. Every time I attempt it, I encounter the following error messages: Can't bind to 'ngFor' since it isn't a known pro ...

Angular Typescript subscription value is null even though the template still receives the data

As a newcomer to Angular and Typescript, I've encountered a peculiar issue. When trying to populate a mat-table with values retrieved from a backend API, the data appears empty in my component but suddenly shows up when rendering the template. Here&a ...

Websocket onmessage event triggered just one time

I have implemented a basic WebSocket client in an Angular 6 application. Everything seems to be working fine, except for the fact that both socket.onmessage and socket.addEventListener('message' are only triggered once. There are no errors in th ...

Two storage locations exhibit distinct behavior when it comes to the favicon

After moving my repository to a new origin and pulling it into a different directory on my computer, I encountered an issue with my .NET Core API and Angular client. The problem is that the new instance of the repository, after being built, does not disp ...

Exploring the world of TypeScript type mappings

I'm currently working on enhancing a function with type annotations. This particular function takes an array of typed objects as parameters and returns a mapped array of a different type: const createAnimals = <T extends AnimalFactory<any>[]& ...

Leverage Custom_Pipe within TS

I am currently working with a pipe that I have created. Here is the code: @Pipe({ name: 'searchNomES' }) export class SearchNomESPipe implements PipeTransform { transform(uos: IUo[], name?: string,): IUo[] { if (!uos) return []; if (!name) ret ...

An Angular module downloaded from npm seems to be lacking the required @NgModule declaration

There seems to be a missing @NgModule and @Directive declarations in an NPM module, even though they exist in the source code on Github. This is causing an issue with importing a directive for databinding from an HTML attribute. I am attempting to utilize ...

The event fails to propagate up to the parent component

I have a project structure set up as follows: https://i.stack.imgur.com/bvmK5.jpg The todo-form component triggers the created event and I am looking to handle this event in the todos component. todo-form.component.html: <form class="todo-form" ( ...

Access Element in Array by Type using TypeScript

Within a TypeScript project, there exists an array of containers that possess a type attribute along with supplementary data based on their individual types. type Container<Type extends string> = { type: Type; } type AContainer = Container<" ...

What is the best way to integrate my Angular keycloak setup with an idphint attribute?

I have successfully integrated the angular keycloak adapter from https://www.npmjs.com/package/keycloak-angular to connect with our keycloak server. Currently, I am exploring the idphint attribute to redirect the request to a different identity provider. ...

Issues arise with the play method in Storybook and Jest when attempting to use the shouldHaveBeenCalled assertion on a

Here is a snippet of the component code: import { FC, ReactElement, useState, MouseEvent as ReactMouseEvent, ChangeEvent as ReactChangeEvent, } from 'react'; import { Stack, TablePagination } from '@mui/material'; export con ...

Having Trouble Adding Details to a New Cart for a User in Angular and MongoDB - What's Going On?

After working on an E-Commerce site for a while, I hit a roadblock. Despite taking a break and coming back with determination, I can't seem to resolve the issue at hand. The application features registration, login, product search, and a popup window ...

typescript in conjunction with nested destructuring

ES6 has definitely made coding more efficient by reducing the number of lines, but relying solely on typescript for everything may not be the best approach. If I were to implement type checking for arguments that have been destructed multiple levels deep, ...

Angular elements nested within each other are causing the ExpressionChangedAfterItHasBeenCheckedError

After conducting thorough research on this issue, I am now uncertain whether it is a bug or an error in my implementation. The problem arises with an element that utilizes a service to retrieve data and then passes it on to a child element. However, upon ...

Ways to shift the focus away from the current date in the Angular Material Datepicker

Is there a way to prevent the focus on today's date when utilizing Angular Material datepicker? I have attempted to include certain properties to mat-datepicker without success. Here is what I have tried: restoreFocus="false" [startAt]="null" &l ...

Having trouble getting the Angular Route to work, any tips on how to fix it?

I am currently learning Angular and have encountered a small issue. When I place the Component in my app.component.html as shown below, it functions correctly: <body> <div class="container"> <app-search-books></app-search-books ...