如何在Angular中使用rxjs运算符加入Observable(angularfire2)

如何在Angular中使用rxjs运算符加入Observable(angularfire2)

问题描述:

我试图找出在Angular中加入Observables的基本知识。我找到了几个例子,但似乎无法弄清楚如何有效地工作。如何在Angular中使用rxjs运算符加入Observable(angularfire2)

我有以下数据结构:

- courses 
    - $courseid1 
    - $courseid2 
    - $courseid3 
    - ... 

- teachers 
    - $teacherid1 
    - $teacherid2 
    - $teacherid3 
    - ... 

- teachersPerCourse 
    - $courseid1 
     - $teacherid1 : true 
     - $teacherid2 : true 
    - $courseid2 
     - $teacherid1 : true 
    - $courseid3 
     - $teacherid3 : true 
    - ... 

现在,我使用下面的函数来获取其塞课程:

getFullCourseBySlug(slug:string) { 
    return this.db.list('academy/courses', { 
    query: { 
    orderByChild: 'slug', 
    equalTo: slug 
    } 
    }).map((courses) => courses[0]); 
} 

现在我想老师的数组映射到课程对象,以便我最终得到一个可观察到的东西,如下所示:

{ 
title: ..., 
slug: ..., 
teachers: { 
    $teacherid1: { 
    firstname: ..., 
    lastname: ..., 
    etc ... }, 
    $teacherid2: { 
    firstname: ..., 
    lastname: ..., 
    etc ... } 
    } 
} 

我在其他地方有相同的原理工作,但我必须在地图功能中使用订阅,或使用Observable内的Observables。例如:

getCoursesPerCategory(categoryid:string):Observable<Course[]> { 
    return this.db.list(`academy/coursesPerCategory/${categoryid}`).map(courses => { 
    courses.map(course => { 
     this.db.object(`academy/courses/${course.$key}`).subscribe((data) => { 
     course.$value = data; 
     }); 
     return course; 
    }); 
    return courses; 
    }); 
} 

如果有人可以帮助我举一个例子,说明如何更有效地做到这一点,将不胜感激!

UPDATE:

我已经成功地得到它的工作,但我仍然无法摆脱嵌套的观测量,这意味着我必须使用特里普尔异步管道(这可能不是最好的做法: P)我试图按照建议使用flatMap,但还不知道如何去做。我现在所拥有的:

getFullCourseBySlug(slug:string): Observable<any> { 
    return this.db.list('academy/courses', { 
    query: { 
     orderByChild: 'slug', 
     equalTo: slug 
    } 
    }).map(courses => courses[0]).switchMap(course => { 

    course.teachers = this.db.list(`academy/teachersPerCourse/${course.$key}`) 
    .map(teachers => { 
     teachers.map(teacher => { 
     teacher.$value = this.db.object(`academy/teachers/${teacher.$key}`); 
     }); 
     return teachers; 
    }); 

    return Observable.of(course); 
    }); 
} 

用下面的模板:

{{ (course | async)?.title }} 

<ul> 
    <li *ngFor="let teacher of ((course | async)?.teachers) | async"> 
    {{ (teacher.$value | async)?.firstname }} 
    </li> 
</ul> 

更新2:

见我的回答对我的解决方案

我会做的是沿着东西以下几行。

首先,我将建立查询课程的方法,像你

getFullCourseBySlug(slug:string) { 
    return this.db.list('academy/courses', { 
    query: { 
    orderByChild: 'slug', 
    equalTo: slug 
    } 
    }).map((courses) => courses[0]); 
} 

然后我会创造你需要执行第二个查询,即取即教师课程的标识之一。

查询的代码可能看起来像

getTeacherIdsPerCourse(course: any) { 
    return this.db.list('academy/teachersPerCourse', { 
    query: { 
    orderByChild: 'slug', 
    equalTo: course.slug 
    } 
    }).map((teacherIds) => [teacherIds, course]); 
} 

看看这个事实,这第二个查询是建立在同时返回teacherIds并已作为参数传递的过程。 现在,您可以使用switchMap运算符连接2个查询。 级联会再像

this.getFullCourseBySlug(slug) 
    .switchMap(course => this.getTeacherIdsPerCourse(course)) 
    .map(([teacherIds, course]) => { 
     // here you have the TeacherIds and the course and therefore you 
     // need to fetch from DB the details for each teacherId and build the 
     // full course object with all the details 
    }) 

现在的问题是如何执行一堆的查询和管理产生可观,因为你需要从教师收集阅读所有其ID已提取与老师第二个查询。

首先构建您需要的第三个查询,即从教师ID开始获取教师所有细节的查询。该代码可能看起来像

getTeacher(id:string) { 
    return this.db.list('academy/teachers', { 
    query: { 
    orderByChild: 'slug', 
    equalTo: slug 
    } 
    }).map((teachers) => teachers[0]); 
} 

如果你可以用HTTP调用的异步回住,也就是说,如果你不需要等待最后老师是牵强,比你能有这样的事情

this.getFullCourseBySlug(slug) 
    .switchMap(course => this.getTeacherIdsPerCourse(course)) 
    .map(([teacherIds, course]) => { 
     for(let id of teacherIds) { 
     this.getTeacher(id).subscribe(teacher => { 
      course.teachers.push(teacher); 
     } 
     } 
    }) 

相反,如果您需要将所有教师的所有详细信息返回到完整课程,那么您需要执行一些更复杂的操作,因为您需要等待所有由教师返回的可观察项getTeacher()方法待解决。

代码这样做可能会像

this.getFullCourseBySlug(slug) 
    .switchMap(course => this.getTeacherIdsPerCourse(course)) 
    .map(([teacherIds, course]) => { 
     const arrayOfObservables = new Array<Observable>(); 
     for(let id of teacherIds) { 
     arrayOfObservables.push(this.getTeacher(id) 
             .map(teacher => course.teachers.push(teacher))); 
     } 
     return Observable.combineLatest(arrayOfObservables): 
    }) 

免责声明:我不是完全肯定的代码是正确的,因为我没有建立一个真正的考验,但简单地组装,我认为相关概念 - 我希望反正我已经给你出个主意

+0

这真的帮了我在正确的方向,最终我设法得到它的工作,因为我祝愿!非常感谢广泛的答复和帮助。我会为其他人发布我的最终解决方案 –

Picci的回答让我在正确的方向,这是我最终的解决方案:

getTeachersPerCourse(courseid:string):Observable<Teacher[]> { 
    return this.db.list(`academy/teachersPerCourse/${courseid}`) 
    .switchMap((teachers) => { 
    let teacherObservables = []; 
    for(let teacher of teachers){ 
     teacherObservables.push(this.db.object(`academy/teachers/${teacher.$key}`)); 
    } 
    return Observable.combineLatest(teacherObservables); 
    }); 
} 

getFullCourseBySlug(slug:string): Observable<any> { 
    return this.db.list('academy/courses', { 
    query: { 
     orderByChild: 'slug', 
     equalTo: slug 
    } 
    }).map(courses => courses[0]).switchMap(course => { 
    return Observable.combineLatest(Observable.of(course), this.getTeachersPerCourse(course.$key), (fullCourse, teachers) => { 
     fullCourse['teachers'] = teachers; 
     return fullCourse; 
    }); 
    }); 
} 

这给了我一个流与课程,和教师的数组作为课程的孩子:

{ 
title: ..., 
slug: ..., 
teachers: [ 
    { 
    firstname: ..., 
    lastname: ..., 
    etc ... 
    }, 
    { 
    firstname: ..., 
    lastname: ..., 
    etc ... 
    } 
    ] 
} 

的观发出任何小孩的任何变化,正是我一直在寻找。而我只需要在我的模板使用一个异步管道:

{{ (course | async)?.title }} 

<ul> 
    <li *ngFor="let teacher of (course | async)?.teachers"> 
    {{ teacher.firstname }} 
    </li> 
</ul> 

希望这有助于其他人:)