Я использую наблюдаемую для запроса моей БД. Этот наблюдаемый вернет массив со всеми найденными совпадающими объектами. Моя проблема в том, что я хочу отобразить наблюдаемое с более подробной информацией, которую я получу из другого API.
Я попробовал concatMap, но он позволил мне вложить только 1 наблюдаемый объект в исходный наблюдаемый объект.
const usersAPI$: Observable<Users[]> = // something
const assistsAPI$: Observable<Assists[]> = // something
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists =>
assists.map(assist => usersAPI$.get(assist.userID)
.pipe(
map(user =>
assist = {...assist}, ...{userName: user.userName}
)
)
)
)
);
Вы можете увидеть аналогичный рабочий пример здесь, на stackblitz, https://stackblitz.com/edit/rxjs-concatmap-issue-stackoverflow где "результат" - это правильный способ использования concatMap и "result2" - это нерабочий способ, который, как я ожидал, будет работать.
@martin the mergeMap вызывает у меня ту же проблему, что и concatMap. (И на самом деле это очень похожие операторы. Я ищу другое решение)
Если mergeMap ведет себя так же, посмотрите, что assistsAPI$.find(), потому что он, вероятно, не испускает предметы, как вы ожидаете.
Бэкенд — FeathersJS. Я уверен в том, что выдает AssistAPI$.find(). Дело не в этом. Но я благодарен за то, что вы пытаетесь помочь, спасибо :)






Вы можете использовать combineLatest() (как статический импорт без канала)
import {combineLatest} from 'rxjs';
const usersAPI$: Observable<Users[]> = // something
const assistsAPI$: Observable<Assists[]> = // something
const combinedObservable$ = combineLatest(usersAPI$,assistsAPI$, someOtherStuff$);
const modifiedAssists$ = combinedObservable$.pipe(
map([usersApiValues, assistsAPIValues, someOtherStuffValues] => {
/** what you want here */
})
);
Просто примите во внимание, что каждый Observables внутри combineLatestдолжен излучать хотя бы один раз (например, вы можете запустить их с пустым массивом)
Мне нужно знать, сколько assistsAPIValues у меня есть, прежде чем запрашивать usersApiValues. Мне нужно преобразовать наблюдаемую assistsAPI$ так, чтобы она возвращала тот же массив из потока, но со свойством userName, уже назначенным каждому assist в assistsмассиве, возвращаемом assistsAPI$
Я верю, что вы хотите mergeMap?
Он отображает внешнюю наблюдаемую в разрешенную внутреннюю наблюдаемую для каждого внешнего излучения.
const result = clicks.pipe(
concatMap(ev =>
interval(1000).pipe(take(4))
)
);
const result2 = clicks.pipe(
mergeMap(ev =>
arr.map(() => interval(1000).pipe(take(4)))
)
);
result.subscribe(x => {
console.info(x)
});
result2.subscribe(x => {
console.info(x)
});
mergeMap (как concatMap ) не решает наблюдаемые, созданные внутренним arr.map(), как предполагалось.
Вы должны каким-то образом обработать свой внутренний массив Observables. Вы можете использовать forkJoin, merge или concat в зависимости от ваших потребностей.
forkJoin будет обрабатывать ваши внутренние вызовы API параллельно и возвращать массив после завершения всех вызовов API. Обратите внимание, что внутренние Observable должны завершиться. Я думаю, это то, что должно подойти вам в вашем приложении.
import { forkJoin } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => forkJoin(assists.map(assist => someObservable ))
);
merge подпишется сразу на все внутренние вызовы API и выдаст результаты всех вызовов один за другим по мере их поступления.
import { merge } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => merge(...assists.map(assist => someObservable )),
// toArray() add the toArray operator if you need the result as an array
);
Это даст вам желаемый результат в вашем stackblitz, но я думаю, что ваш stackblitz несколько вводит в заблуждение, а не то, что вы ищете в примере кода из вашего вопроса, поскольку внутренний Observable в вашем stackblitz испускает несколько раз, а окончательный вывод не массив. Если порядок внутренних запросов не имеет значения, все они выдают одно значение, а затем завершаются, и вам нужны результаты всех запросов в виде массива, просто используйте forkJoin.
concat подпишется на все вызовы внутреннего API один за другим. Следующий Observable в последовательности будет подписан только после завершения предыдущего. Поэтому выполнение будет медленнее, чем с forkJoin или merge, поскольку следующий HTTP-запрос будет выполнен только после того, как предыдущий вернет значение. Используйте это, если вызовы вашего userAPI должны быть сделаны в том же порядке, что и assists в вашем массиве.
import { concat } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => concat(...assists.map(assist => someObservable )),
// toArray() add the toArray operator if you need the result as an array
);
Спасибо! Ваше решение concat сработало очень хорошо для той цели, которую я хотел (плюс с toArray(), как вы тоже предложили)!
Вы можете использовать
mergeMapвместоconcatMap.