Javascript RxJS:在订阅之前修改可观察数组

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:

我正在从一个API中获取数据(
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。