2017-06-14 45 views
0

我試圖找出在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:

見我的回答對我的解決方案

回答

1

我會做的是沿着東西以下幾行。

首先,我將建立查詢課程的方法,像你

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

這真的幫了我在正確的方向,最終我設法得到它的工作,因爲我祝願!非常感謝廣泛的答覆和幫助。我會爲其他人發佈我的最終解決方案 –

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> 

希望這有助於其他人:)

相關問題