2017-02-23 1 views
1
const placeId = this.getPlaceId(); 
     this.af.database.list(`placeUsers/${placeId}`).subscribe((userKeys) => { 
      for (let index = 0; index < userKeys.length; index++) { 
       let userKey = userKeys[index]; 

       this.af.database.list(`userDevices/${userKey.$key}`).subscribe((deviceKeys) => { 

        for (let index = 0; index < deviceKeys.length; index++) { 
         let deviceKey = deviceKeys[index]; 

         this.af.database.object(`devices/${deviceKey.$key}`).subscribe((device) => { 

          console.log(device); 
          // Device received.  

         }); 
        } 
       }); 
      } 
     }); 

현재 장소를 팔로우하는 모든 사용자에게 알림을 보내려합니다.여러 FirebaseListObservables 결합하기

  • (userDevices 노드)
  • deviceKeys에서 장치를 얻기 (placeUsers 노드)
  • 사용자에 속하는 deviceKeys 얻기 장소에 속한 사용자 얻기 (: 전류의 흐름은 다음과 같이 진행 devices 노드)

이러한 모든 호출을 하나의 관찰 가능한 호출로 결합하는 방법이 있는지 궁금합니다.

현재 나의 문제점은 이러한 모든 요청이 언제 완료되었는지를 알 수 없다는 것입니다. RxJ를 살펴 봤는데,이 모든 관측 자료를 결합 할 수 있습니다. 그러나 나는 4 개의 노드로 그것을하는 방법에 대한 좋은 해결책을 찾지 못했습니다.

답변

1

concatMapforkJoin을 사용하여 장치를 방출하는 관찰 가능 항목을 구성 할 수 있습니다. 관찰로 구성된이 장치의 단일 배열을 방출 할 것이다 것입니다 다음 완료합니다 (first 연산자는 첫 번째 방출 목록 또는 개체 걸릴 사용되는) :

import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/concatMap'; 
import 'rxjs/add/operator/first'; 
import 'rxjs/add/operator/forkJoin'; 

this.af.database 
    .list(`placeUsers/${placeId}`) 
    .first() 
    .concatMap(userKeys => { 
    let observables = userKeys.map(userKey => this.af.database 
     .list(`userDevices/${userKey.$key}`) 
     .first() 
    ); 
    return observables.length ? 
     Observable.forkJoin(...observables, (...lists) => [].concat(...lists)) : 
     Observable.of([]) 
    }) 
    .concatMap(deviceKeys => { 
    let observables = deviceKeys.map(deviceKeys => this.af.database 
     .object(`devices/${deviceKey.$key}`) 
     .first() 
    ); 
    return observables.length ? 
     Observable.forkJoin(...observables) : 
     Observable.of([]) 
    }) 
    .subscribe(devices => console.log(devices)); 

당신이 완전하고를 방출하지 않는 것을 관측을 원하는 경우를

import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/combineLatest'; 
import 'rxjs/add/operator/switchMap'; 

this.af.database 
    .list(`placeUsers/${placeId}`) 
    .switchMap(userKeys => { 
    let observables = userKeys.map(userKey => this.af.database 
     .list(`userDevices/${userKey.$key}`) 
    ); 
    return observables.length ? 
     Observable.combineLatest(...observables, (...lists) => [].concat(...lists)) : 
     Observable.of([]) 
    }) 
    .switchMap(deviceKeys => { 
    let observables = deviceKeys.map(deviceKeys => this.af.database 
     .object(`devices/${deviceKey.$key}`) 
    ); 
    return observables.length ? 
     Observable.combineLatest(...observables) : 
     Observable.of([]) 
    }) 
    .subscribe(devices => console.log(devices)); 
+1

어떤 목적으로 관찰 배열에 확산 연산자를 사용하지 (:는 A 장소에 대한 사용자 또는 기기 변경, switchMap 대신 concatMap를 사용하는 대신 forkJoincombineLatestfirst 연산자를 제거 할 때마다 장소를 장치 '... observab les')는'forkJoin'과'combineLatest'가 각각 배열 인자를 취할 수 있다면 여기에서 제공됩니까? – patrickmcd

+0

@patrick 기술적 인 이유는 없습니다. 가능한 한 간단하게 긴 답변을 작성하는 것입니다. (그와 같은) 문서는 배열을 전달할 수 있다는 것을 분명히하지 않으므로 설명 할 필요가 없습니다. 또한, 베타 테스트 중에 배열 인수를 허용하지 않는 연산자가 있지만 구문이 모두 분산되어 있음을 기억합니다. – cartant

+1

@patrick 방금 문을 두드렸으므로 확산 구문을 선호하는 또 다른 이유를 제시 할 수 있습니다. 'Observable.concat'과 같은 몇몇 메소드는 배열을 [ObservableInput] (http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObservableInputDoc.html)으로 취급 할 것이고 배열의 요소들을 연결시킬 것입니다 - 그래서 확산 된 구문이 사용된다면 메소드간에 메소드가 더 일관성이 있다고 생각합니다. – cartant