rxjs - объединение внутренних наблюдаемых после фильтрации - PullRequest
0 голосов
/ 29 августа 2018

Я звоню бэкэнду, который отвечает:

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

Каждый JSON может иметь следующую схему:

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

Я хочу получить массив со всеми данными, для которых isValid имеет значение true

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

Когда в обоих .json для "isValid" установлено значение true, я получаю массив с обоими данными. Но когда для одного из них для isValid установлено значение false, наблюдаемое никогда не завершается.

Я мог бы использовать mergeAll вместо объединить все, но тогда я получаю поток отдельных данных, а не сбор всех данных.

Есть ли лучший способ отфильтровать наблюдаемые?

Ответы [ 2 ]

0 голосов
/ 30 августа 2018
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));
0 голосов
/ 29 августа 2018

Как вы сказали, внутренняя наблюдаемая никогда не излучает, потому что filter не передает единственное значение, которое когда-либо испускается наблюдаемой backend.get. В этом случае оператор, подписывающийся на это наблюдаемое - в вашем случае combineAll - также никогда не получит никакого значения и никогда не сможет выдать себя.

Я бы просто переместил фильтрацию и отображение на combineAll, предоставив функцию проекта, например:

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)
        )
    )

Посмотрите, подходит ли вам это;)

...