rxjs - combining inner observables after filtering

跟風遠走 提交于 2019-12-11 05:23:40

问题


I call backend that respond with:

[
  "https://some-url.com/someData1.json",
  "https://some-url.com/someData2.json"
]

Each JSON can have following schema:

{
  "isValid": boolean,
  "data": string
}

I want to get array with all data, that have isValid is set to true

backend.get(url)
    .pipe(
        mergeMap((urls: []) =>
            urls.map((url: string) =>
                backend.get(url)
                    .pipe(
                        filter(response => response.isValid),
                        map(response => response.data)
                    )
            )
        ),
        combineAll()
    )

When both .json have "isValid" set to true, I get array with both data. But when one of them has "isValid" set to false observable never completes.

I could use mergeAll instead of combineAll, but then I receive stream of single data not collection of all data.

Is there any better way to filter out observable?


回答1:


As you said, the inner observable never emits, because filter does not forward the only value that is ever emitted by the backend.get observable. In that case, the operator subscribing on that observable - in your case combineAll - will also never receive any value and cannot ever emit itself.

What I would do is just move the filtering and mapping to combineAll by providing a project function, like that:

backend.get(url)
    .pipe(
        mergeMap((urls: string[]) =>
            urls.map((url: string) => backend.get(url))
        ),
        combineAll(responses =>
            responses
                .filter(response => response.isValid)
                .map(response => response.data)
        )
    )

See if that works for you ;)




回答2:


import { forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

interface IRes {
  isValid: boolean;
  data: string;
}

interface IResValid {
  isValid: true;
  data: string;
}

function isValid(data: IRes): data is IResValid {
  return data.isValid;
}

const res1$: Observable<IRes> = backend.get(url1);
const res2$: Observable<IRes> = backend.get(url2);

// When all observables complete, emit the last emitted value from each.
forkJoin([res1$, res2$])
  .pipe(map((results: IRes[]) => results.filter(isValid)))
  .subscribe((results: IResValid[]) => console.log(results));


来源:https://stackoverflow.com/questions/52081255/rxjs-combining-inner-observables-after-filtering

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!