rxjs с несколькими forkjoin при выполнении http-запросов

Я делаю некоторые http-запросы и использую rxjs для успешного уведомления о результате:

  getReportings(departmentId: number): Observable<any> {
        return Observable.forkJoin(
            this.http.get('/api/members/' + departmentId).map(res => res.json()),
            this.http.get('/api/reports/' + departmentId).map(res => res.json())
        );
    }

Когда оба HTTP-запроса выполнены, я хочу, чтобы внутри метода getReportings выполнялась итерация массива отчетов, считывались некоторые значения и для каждого отчета снова выполнялся новый HTTP-запрос с этими значениями.

Всего у меня 2 (член/отчеты) + ок. От 4 до 8 (другие вещи) запросов.

Когда все ок. Выполнено от 6 до 8 запросов. Я хочу получить ВСЕ данные из предыдущих 6-8 запросов в успешном обработчике.

Как я могу сделать это с помощью rxjs?

ОБНОВИТЬ

Поскольку пользователь olsn запросил более подробную информацию, и теперь я понимаю его, что его беспокоит, я помещаю здесь больше данных (псевдокод), как должны выглядеть запросы с 6 по 8:

getReportings(departmentId: number): Observable<any> {
    return Observable.forkJoin(
        this.http.get('/api/members/' + departmentId).map(res => res.json()),
        this.http.get('/api/reports/' + departmentId).map(res => res.json())
    ).switchMap((result: [any[], any[]]) => {
        let members: any[] = result[0];
        let reports: any[] = result[1];
        let allNewStreams: Observable<any>[] = [
            Observable.of(members),
            Observable.of(reports)
        ]; 

        for(let report of reports)
        {
            allNewStreams.push(
this.http.get(report.url + ?key1=report.name1?).map(res => res.json()));
        }


        return Observable.forkJoin(allNewStreams); // will contain members, reports + 4-6 other results in an array [members[], reports[], ...other stuff]
    });
}

person Elisabeth    schedule 17.12.2016    source источник


Ответы (1)


Вы можете расширить свой поток, используя switchMap, например:

getReportings(departmentId: number): Observable<any> {
    return Observable.forkJoin(
        this.http.get('/api/members/' + departmentId).map(res => res.json()),
        this.http.get('/api/reports/' + departmentId).map(res => res.json())
    ).switchMap((result: [any[], any[]]) => {
        let members: any[] = result[0];
        let reports: any[] = result[1];
        let allNewStreams: Observable<any>[] = [
            Observable.of(members),
            Observable.of(reports)
        ];
        // do your stuff and push new streams to array...
        if (foo) { // for each additional request
            let reportId: string | number = reports[0].id; // or however you retrieve the reportId
            allNewStreams.push(
                this.http.get('some/api/ + bar)
                    .map(res => res.json())
                    .map(data => ({reportId, data})); // so your final object will look like this: {reportId: "d38f68989af87d987f8", data: {...}}
            );
        }

        return Observable.forkJoin(allNewStreams); // will contain members, reports + 4-6 other results in an array [members[], reports[], ...other stuff]
    });
}

Это должно сработать, это больше похоже на подход "старомодного логического молотка" — если вы его ищете: может быть более элегантный способ решить эту проблему с помощью других операторов, но это трудно сказать, не зная полных данных и всей логики.

person olsn    schedule 17.12.2016
comment
Спасибо! Действительно ли значение переменных позволит найти лучшее техническое решение? Больше нет логики в отношении http-запросов. Логика начинается, когда один сервисный вызов на стороне клиента получает все данные http-запроса, на которые он подписан. Каких полных данных вам не хватает? - person Elisabeth; 18.12.2016
comment
Вопрос в том, как определяются другие 4-6 запросов, насколько я понимаю, что они зависят от определенных данных из запросов членов + отчетов и могут вызываться или не вызываться - это может быть основано на количестве отчетов... это может быть основано на некоторых флагах в отчете... или... или... и т. д... в зависимости от того, что могут использоваться разные операторы rxjs - в любом случае if/else -way должен работать не меньше. - person olsn; 18.12.2016
comment
Только что проверил код, все работает. Но по ходу дела я понимаю, что у меня все еще есть проблема. все 4-8 запросов «могут» прийти в случайном порядке в ответ. Я не хочу оставлять на уме автора rxjs ;-) Что касается моего псевдокода, можно ли передать каждый из 4-8 запросов report_Id ПОСЛЕ выполнения http-запросов? Я хочу иметь связь возвращаемых данных с каждым отчетом. Допустим, каждый отчет отчетов имеет идентификатор, и вместо возврата массива данных для каждого запроса report.url я возвращаю объект с report_Id и возвращенными данными :-) - person Elisabeth; 18.12.2016
comment
Конечно, просто добавьте дополнительный .map(...) - порядок в вашей подписке не должен быть случайным, независимо от времени выполнения, поскольку forkjoin будет распространять данные только после того, как все запросы будут выполнены - и их порядок будет таким же, как и входной массив. - person olsn; 18.12.2016
comment
Я согласен с тем, что порядок allNewStreams и его наблюдаемых элементов одинаков, когда я получаю успешный ответ и его массивы, НО в моем компоненте.ts я не знаю, как материал был сопоставлен в моем reportservice.ts, поэтому мне наконец нужны ссылки :-) Не могли бы вы показать мне немного больше, пожалуйста, как бы вы использовали метод .map() для сопоставления каждого report.id с вызывающими 4-8 запросами? - person Elisabeth; 18.12.2016
comment
Верно - я расширил пример в своем ответе дополнительным .map(...) - person olsn; 18.12.2016