我正在使用可观察的查询我的数据库。 此可观察对象将返回一个包含所有找到的匹配对象的数组。 我的问题是我想将可观察对象与将从另一个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”是我期望的非工作方式
答案 0 :(得分:1)
您必须以某种方式处理内部的Observable数组。您可以根据需要使用viewA.isHidden = true
,forkJoin
或merge
。
concat
将并行处理内部API调用,并在所有API调用完成后返回一个数组。注意内部的Observable必须完成。我认为这应该适合您的应用程序。
forkJoin
import { forkJoin } from 'rxjs';
const modifiedAssists$ = assistsAPI$.find().pipe(
concatMap(assists => forkJoin(assists.map(assist => someObservable ))
);
将立即订阅所有内部API调用,并在所有调用到达时逐一发出结果。
merge
这将使您的stackblitz获得理想的结果,但是我认为您的stackblitz有点误导,而不是您在问题示例代码中寻找的内容,因为stackblitz中的内部Observable会发出多次,并且最终输出不是数组。如果内部请求的顺序无关紧要,它们都将发出一个值,然后完成,您需要将所有请求的结果作为数组,只需使用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
);
。
forkJoin
将一个接一个地订阅所有内部API调用。序列中的下一个Observable仅在上一个完成后才订阅。因此,执行将比使用concat
或forkJoin
慢,因为下一个HTTP请求仅在前一个返回值之后才执行。如果对您的merge
的调用必须与数组中的userAPI
相同,请使用此命令。
assists
答案 1 :(得分:0)
您可以使用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 */
})
);
只需考虑,combineLatest
中的每个可观察对象应该至少发射一次(例如,您可以使用一个空数组作为开始)
答案 2 :(得分:0)
我相信您想要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.log(x)
});
result2.subscribe(x => {
console.log(x)
});