Search code examples
javascriptfirebaserxjssubscription

Javascript: Combine Multiple Subscription Result into One Array


I am trying to get data from one subscription and based on the data, I am calling nested subscription to add to the data object. This is how my function looks like:

this.subCatSubscription = this.afDatabase.list('/sub-categories/').snapshotChanges().subscribe((subCat: any) => {
      this.categories = [];
      subCat.forEach( sc => {
        if(sc.payload.val().category) {
          this.cat1Subscription = this.afDatabase.list('/categories/').snapshotChanges().subscribe((cat: any) => {
            cat.forEach(c => {
              if(c.key === sc.payload.val().category) {
                this.categories.push({ key: sc.key, ...sc.payload.val(), parentCatName: c.payload.val().name });
                //this.categories.sort((a, b) => a.name.localeCompare(b.name));
              }
            });
          });
        } else {
          this.categories.push({ key: sc.key, ...sc.payload.val() });
          //this.categories.sort((a, b) => a.name.localeCompare(b.name));
        }
        console.log(this.categories)
      });
    })

Is there any way to combine the two above subscription and get the desired data based on the condition I have?

Thanks.


Solution

  • When you remove the observables from your example, what you're trying to do is create an array of objects while some are mutated from a second array. What I've provided is the following steps.

    1. Get sub-category data.
    2. Create the array of default objects.
    3. Get the parent category data.
    4. For each sub-category that contains a parent match, mutate the object. Otherwise, return the object as is.

    For step 3 (Get the parent category data) we can do this with a simple switchMap().

      this.categories$ = this.afDatabase
        .list("/sub-categories")
        .snapshotChanges()
        .pipe(
            map(subCategories=>
                subCategories.map(sc=>({ key: sc.key, ...sc.payload.val() }))
            ),
            switchMap(categories=>this.afDatabase
                .list("/categories/")
                .snapshotChanges()
                .pipe(
                    map(parent=>
                        categories.map(c=>{
                            const match = parent.find(pc=>pc.key === c.category);
                            return !!match ? {...c, parentCatName: match.payload.val().name} : c
                        })
                    )
                )
            )
        );
    

    Now, we're only requesting /categores/ once instead of multiple times for each match.