【问题标题】:RxJs Compose a list of Observables and then combine (Firebase)RxJs 组成一个 Observable 列表,然后组合(Firebase)
【发布时间】:2017-06-18 17:20:23
【问题描述】:

我正在尝试合并一个可观察的列表,但没有使用 zip 或其他地图的运气。

我想做的是获取给定艺术家 ID 的流派列表。我使用的是firebase,所以它是一个nosql 数据库。我有一个“genresPerArtist”列表,它是一个艺术家键列表,每个艺术家键都有一个流派键列表。 结构:

    { 
         genresPerArtist: {
             artist1: {
                 genre1: true,
                 genre2: true,
                 genre3: true
            }
        },
         genres: {
             genre1: {
                name: 'Alternative'
             },
             genre2: {
                name: 'Jazz'
             } 
        }
    }

这是我拥有的功能的开始:

getGenresByArtistId(artistId: string): Observable<any> {
     return this.db.list(`/genresPerArtist/${artistId}`)
         .flatMap((genres: IDictionary[]) => {
             return genres.map(genre => this.db.list(`/genres/${genre.$key}`));
             // return Observable.zip(obvs);
         });

我不太确定如何处理我从genresPerArtist 获得的列表。我想要做的是获取每个genre.key(genre1,genre2,genre3),并使用每一个从'genres'中获取值。我以为我可以返回一个 .zip,然后对其进行映射,但我没有得到 zip 的响应。

【问题讨论】:

  • “流派”的值是指与流派键关联的整个对象?您能否指定方法的返回类型? (可观察的 很有帮助)
  • 是的,我想我会得到与流派键相关联的整个对象。我最终会从中得到 'name' 属性。
  • 少数元素应该是数组,您将它们全部显示为对象
  • @cartant,谢谢,forkJoin 是我需要的,请参阅我发布的答案。如果您想发布答案,可以,我会标记为正确。

标签: firebase firebase-realtime-database rxjs


【解决方案1】:

@cartant,谢谢,这包括我需要的东西,forkJoin

// Compose an observable based on the genresPerArtist:
        return this.db.list(`/genresPerArtist/${artistId}`)
        // Each time the genresPerArtist emits, switch to unsubscribe/ignore any pending user queries:
        .switchMap(genres => {
            // Map the genres to the array of observables that are to be joined.
            let genreObservables = genres.map(genre => this.db.object(`/genres/${genre.$key}`).first());
            return Observable.forkJoin(...genreObservables);
        });

【讨论】:

    【解决方案2】:

    您可以尝试以下方法,假设 genresPerArtist 的返回返回 Map&lt;string, boolean&gt;

    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/mergeMap';
    import { zip } from 'rxjs/observable/zip';
    
    getGenresByArtistId(artistId: string): Observable<Genre[]>{
       return this.db.list(`/genresPerArtist/${artistId}`)
       .mergeMap((genres: Map<string, boolean>) => 
        zip(Array.from(genres.keys()).map(genre => this.db.list(`/genres/${genre}`))))
    }
    

    编辑:另一种选择是

    import 'rxjs/add/operator/mergeMap';
    import 'rxjs/add/operator/toArray';
    
    getGenresByArtistId(artistId: string): Observable<Genre[]>{
           return this.db.list(`/genresPerArtist/${artistId}`)
           .mergeMap((genres: Map<string, boolean>) => Array.from(genres.keys())
           .mergeMap(genres=> genres)
           .mergeMap(genre => this.db.list(`/genres/${genre}`))
           .toArray();
        }
    

    基本上我手动将结果展平为单个数组。我花了很长的路来让它更容易跟随

    【讨论】:

    • 看来mergeMap和flatMap是一样的。这里的问题是,如果我从 getGenresByArtistId 订阅发出的 observable,它永远不会解决。 (它被调用,但从不返回任何项目)
    • 是的,flatMap 是 mergeMap 的别名。你有任何错误吗?是否发送了第一个请求 (genresPerArtis)?
    • 没有错误。是的,/genresPerArtist 被发送并解析,它们也为每个流派构建了 Observables 数组。但是当我订阅最终结果时,什么都没有解决。
    • 很高兴,让我们尝试另一种变体
    • @mrshickadance 运气好吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    • 2020-06-19
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多