Javascript RxJS:在订阅之前修改可观察数组
我正在从一个API中获取数据(Javascript RxJS:在订阅之前修改可观察数组,javascript,typescript,rxjs,observable,Javascript,Typescript,Rxjs,Observable,我正在从一个API中获取数据(students,该API返回一个可观察的数据。在这个结果中,我需要从两个不同的表中获取数据并合并结果 以下是我的简化界面: export interface student Student { id: string name: string, school_id: string, classroom_id: string } export interface school School { id: string, name:
students
,该API返回一个可观察的数据。在这个结果中,我需要从两个不同的表中获取数据并合并结果
以下是我的简化界面:
export interface student Student {
id: string
name: string,
school_id: string,
classroom_id: string
}
export interface school School {
id: string,
name: string
}
export interface classroom Classroom {
id: string,
name: string
}
我现在需要通过外键学校id
和教室id
获取所有学生
,并为每个学生
添加相应的学校
和教室
我目前的做法如下。我知道它还没有完成,但我无法找到合适的操作员以及如何正确使用它
this.getStudents().pipe(
switchMap(students => {
student.map(student => forkJoin([
this.getSchool(student.school_id),
this.getClassroom(student.classroom_id)
]))
})
)
所有的方法(getStudents()
,getSchool()
,getSchool()
)都返回可观察值。我的目标是在订阅后获得一组学生
,以及相应的学校
和教室
数据
如果需要获取单个学生(例如使用getStudent()
),然后使用combinelatetest
组合多个流,我知道如何完成。但是当获取多个学生时,情况就不同了
提前谢谢你 您需要forkJoin
从student.map()
获取的可观察数组,并使用map
将结果投影到所需对象中
const result$ = getStudents().pipe(
switchMap((students: Student[]) =>
forkJoin(students.map(student =>
forkJoin([
getSchool(student.school_id),
getClassroom(student.classroom_id)
]).pipe(map(([school, classroom]) => ({
student,
school,
classroom
}))
)
))
));
您需要forkJoin
从student.map()
获得的可观察数组,并使用map
将结果投影到所需对象中
const result$ = getStudents().pipe(
switchMap((students: Student[]) =>
forkJoin(students.map(student =>
forkJoin([
getSchool(student.school_id),
getClassroom(student.classroom_id)
]).pipe(map(([school, classroom]) => ({
student,
school,
classroom
}))
)
))
));
您可以做的是将原始数组结果转换为一个流,该流发送每个学生并逐个构造每个记录。构建对象后,可以使用toArray()将其返回到单个数组结果。我发现这样做(将发射阵列的流展平为发射单个元素的流)由于嵌套减少而更容易管理
this.getStudents().pipe(
switchMap(students => students), // emit each element individually
concatMap(student => // construct the student object.
forkJoin({
classRoom: this.getClassroom(student.classroom_id),
school: this.getSchool(student.school_id),
student: of(student)
})
),
toArray() // when all results are built, emit one array result.
);
如果getStudents()返回一个发射,然后完成,则此技术效果最佳。如果observable保持打开状态,则toArray()将不会发出,因为它仅在源observable完成时执行
如果它确实保持打开状态,但您只需要第一个阵列发射,则在管道的开头添加take(1)或first()即可
您可以做的是将原始数组结果转换为一个流,该流发送每个学生并逐个构造每个记录。构建对象后,可以使用toArray()将其返回到单个数组结果。我发现这样做(将发射阵列的流展平为发射单个元素的流)由于嵌套减少而更容易管理
this.getStudents().pipe(
switchMap(students => students), // emit each element individually
concatMap(student => // construct the student object.
forkJoin({
classRoom: this.getClassroom(student.classroom_id),
school: this.getSchool(student.school_id),
student: of(student)
})
),
toArray() // when all results are built, emit one array result.
);
如果getStudents()返回一个发射,然后完成,则此技术效果最佳。如果observable保持打开状态,则toArray()将不会发出,因为它仅在源observable完成时执行
如果它确实保持打开状态,但您只需要第一个阵列发射,则在管道的开头添加take(1)或first()即可
谢谢,我有类似的想法,但如果我订阅result$,它是空的。还通过Angular的异步管道进行了测试。我是否错过了这里的“返回”?getStudents()方法本身返回值,我已经检查过了!我必须通过使用.pipe(take(1)),确保第二个forkJoin getSchool()和get教室()中的可观察对象只返回一个值。谢谢,我也有类似的想法,但是如果我订阅result$,它是空的。还通过Angular的异步管道进行了测试。我是否错过了这里的“返回”?getStudents()方法本身返回值,我已经检查过了!通过使用.pipe(take(1))+1,我必须确保第二个forkJoin getSchool()和get教室()中的可观察对象只返回一个值。我喜欢这种方法。两个注意事项:1)在switchMap
中不必使用of
。如果返回数组,它将单独发射元素。2) 我建议用mergeMap
代替concatMap
,这样可以同时进行多个调用。Ty@BizzyBob,我不知道从switchMap返回数组可以做到这一点,这是一个有用的提示。switchMap
采用了一个类型为(x:t)=>Observable | Promise | U[]
的函数,就像所有育肥运算符一样,在使用“toArray()”时,我的订阅不会返回结果。如果我移除`toArray()'),我会得到结果,但会单独得到,而不是作为数组。然而,感谢您的解决方案@DanielGimenezI假设学生只给出一个结果。如果它发出多个结果,并保持打开状态,则toArray将永远不会发出。如果您只想从this.getStudents获得第一次发射,请使用切换图之前的take。+1我喜欢这种方法。两个注意事项:1)在switchMap
中不必使用of
。如果返回数组,它将单独发射元素。2) 我建议用mergeMap
代替concatMap
,这样可以同时进行多个调用。Ty@BizzyBob,我不知道从switchMap返回数组可以做到这一点,这是一个有用的提示。switchMap
采用了一个类型为(x:t)=>Observable | Promise | U[]
的函数,就像所有育肥运算符一样,在使用“toArray()”时,我的订阅不会返回结果。如果我移除`toArray()'),我会得到结果,但会单独得到,而不是作为数组。然而,感谢您的解决方案@DanielGimenezI假设学生只给出一个结果。如果它发出多个结果,并保持打开状态,则toArray将永远不会发出。如果您只需要this.getStudents的第一次发射,请在切换贴图之前使用take。