Search code examples
rxjsobservablerxjs5

How to flatten an Observable<Observable<any>> to Observable<any>?


I am trying to get an Observable<MyType> by doing the following:

return this.cache.get<MyType, number>(storageName, version)
    .map(cached => {
        if (cached !== undefined) {
            return cached;
        }
        return this.http.get<MyType>(`MyTypeGetUrl/${version}`)
            .map(m => m)
            .do(result => {
                this.cache.put<MyType>(storageName, result).first().subscribe();
            });
        }).publishReplay(1).refCount();

cache.get returns an Observable<MyType> and http.get<T> returns Observable<T>.

I want check the cache for an object, and if it doesn't exist, get it from the server, cache it and return it.

However, if the object exists in the cache, it returns Observable<MyType>, but if it needs to go to the server, it returns Observable<Observable<MyType>>.

How can I flatten the result from the server, so that I can return an Observable, only calling to the server when I must?


Solution

  • Instead of map use mergeMap and wrap the cached result into an Observable. In both cases it'll go through mergeMap so it'll unwrap Observable<MyType> into MyType (you could use concatMap or switchMap as well in this example).

    return this.cache.get<MyType, number>(storageName, version)
      .mergeMap(cached => {
        if (cached !== undefined) {
          return Observable.of(cached);
        }
        return this.http.get(...);
      })
      ...