Search code examples
angulartypescriptrxjsobservableswitchmap

angular how to get array of nested object from two tables one-to-many related


Hi everybody I have 2 mysql tables: itemsClass which contains a list of possible classes, and itemType which refers to itemClass and contains type values of a particular class.

I'm trying to build a service which returns an Observable<Item[]>, combining two http.get Observables, suiting this interface:

interface Item{
 itemcClassId:any; //itemClass.id, from itemClass select
 itemClassName:any; //itemClass.name from itemClass select
 itemTypeValue?:any;    //from itemType select, if itemType contains only a value of the first table's class
 itemTypeValues?:any[]; //if itemType's values are multiple
}

I came across (after infinite searches) a code structure like this

getEmploye(name: string): Observable<any> {
    return this.getClass(name).pipe(
      switchMap((response) => {
        return forkJoin(of(response),this.getType(class.id);),
               map(res=>{
                 return {...res[0],values:...res[1]}
               })
      })
    ) 
  }

but it would return a single item while I need an array of items.. any hint?

thank everybody

EDIT: the code I pasted wasnt customized, just pasted because it seemed to comply with similar needs (or at least part of);

A customized version (returning only one item) would consist in (as far as I can understand) something like the following:

getItem(id: number): Observable<Item> {
    return this.http.get(url_to_ItemClass_rest_api).pipe(
      switchMap((item) => {
        return forkJoin(of(item),
this.http.get(url_to_ItemType_rest_api_filtered_by_foreign_key_item.id/);),
               map(res=>{
                 return {...res[0],values:...res[1]}
               })
      })
    ) 
  }

Solution

  • forkjoin is deprecated in that mode. You have to pass an array::

    forkjoin([of(item),
    this.http.get(url_to_ItemType_rest_api_filtered_by_foreign_key_item.id/)])
    

    If you want a single return with key and value, you can return something like this: const ret = { ...res[0], values: res[1] };

      getEmploye(id: number): Observable<any> {
        return this.getClass(id).pipe(
          switchMap(item => {
            return forkJoin([of(item), this.getType(item.id)]).pipe(
              map(res => {
                const ret = { ...res[0], values: res[1] };
                return ret;
              })
            );
          })
        );
      }
    

    For the Array try something like this:

    getClass(name: number): Observable<Array<{id: string}>>

    getType(classId: string): Observable<Array< string >>

    getEmploye(id: number): Observable<any> {
        return this.getClass(id).pipe(
          switchMap(items => {
            const forkRequest: Array<any> = [of(items)];
            items.forEach( item => forkRequest.push(this.getType(item.id)));
    
            return forkJoin(forkRequest).pipe(
              map((res: Array<any>) => {
                const returnList: Array<{id: string, values: Array<any>}> = [];
                res.forEach((item: any, index: number) => {
                  if (index > 0) {
                    const returnObj = { id: res[0][index - 1].id, values: item };
                    returnList.push(returnObj);
                  }
                });
                return returnList;
              })
            );
          })
        );
      }