简体   繁体   中英

value from Observable within Observable using angularfire2 firestore

I am trying to query a sub-collection if exists while querying for document from collection . My first query returns/maps data properly but when I try to query the subcollection it will be stored as observable within the Observable<data> . Below is what I have/tried so far.

component.ts

availableCategoriesCollection: AngularFirestoreCollection<Category>;
availableCategories$: Observable<CategoryId[]>;
lstCategories: Observable<any>;

this.availableCategoriesCollection = this.httpDataService.getAllCategories();
this.availableCategories$ = this.availableCategoriesCollection.snapshotChanges().map(data => {
  return data.map(record => {
    const rec = record.payload.doc.data() as Category;
    const cId = record.payload.doc.id;
    return {cId, ...rec};
  });
});

this.lstCategories = this.availableCategories$.map(data => {
  return data.map((rec: CategoryId) => {
    //if a category has subcategory then query the document again for subcollection
    if (rec.hasSubCat) {
      return this.httpDataService.getSubCategory(rec.cId).snapshotChanges().concatMap(d => {
        return d.map(r => {
          const arr: any = {};
          arr.id = r.payload.doc.id;
          arr.itemName = (r.payload.doc.data() as Category).categoryName;
          arr.category = rec.categoryName;
          return arr;
        });
      });
    }else {
      const arr: any = {};
      arr.id = rec.id;
      arr.itemName = rec.categoryName;
      arr.category = 'All';
      return arr;
    }
  });
});

When I look into the lstCategories value, the documents that have subcollection will be returned as Observable and the ones which don't have subcollection returns proper data with id , itemName and category . Something like below:

(9) [{…}, Observable, Observable, {…}, {…}, {…}, {…}, {…}, Observable]

How can I properly subscribe to the sub-query ? What am I missing here?

So your problem is that the map s callback sometimes returns a plain object and sometimes returns an Observable. I guess you still want to emit an array of objects (including those inside the inner Observables) instead of emitting items one by one.

I think the easiest way to do this is using forkJoin and always returning an Observable (even when the result could be a plain object):

this.lstCategories = this.availableCategories$.mergeMap(data => {
  const observables = data.map((rec: CategoryId) => {
    if (rec.hasSubCat) {
      return this.httpDataService... // Observable
    } else {
      const arr: any = {};
      ...
      return Observable.of(arr); // Observable
    }
  }

  return Observable.forkJoin(observables);
});

Also notice that I had to use this.availableCategories$.mergeMap() because mergeMap will subscribe to the forkJoin Observable and emit its result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM