在Angularfire2中"加入"Firebase查询

J. *_*nor 6 firebase typescript firebase-realtime-database angularfire2 angular

更新:

我遇到的空值字段的问题与我的数据库中不存在的键有关,所以这里的大部分话语都不适用于你的问题.如果您正在寻找一种在AngularFire2中"加入"查询的方法,下面接受的答案可以很好地解决这个问题.我正在使用combineLatest而不是forkJoin.为了做到这一点,你必须这样做import 'rxjs/add/observable/combineLatest';.

我有以下非规范化的Firebase结构:

members
  -memberid1
    -threads
       -threadid1: true,
       -threadid3: true
    -username: "Adam"
    ...

threads
  -threadid1
      -author: memberid3
      -quality: 67
      -participants
         -memberid2: true,
         -memberid3: true
     ...
Run Code Online (Sandbox Code Playgroud)

我想username在我的threads视图中渲染,它按照排序quality.

我的服务:

getUsername(memberKey: string) {
    return this.af.database.object('/members/' + memberKey + '/username')
}

getFeaturedThreads(): FirebaseListObservable<any[]> {
    return this.af.database.list('/threads', {
        query: {
            orderByChild: 'quality',
            endAt: 10
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我的组件:

ngOnInit() {
    this.threads = this.featuredThreadsService.getFeaturedThreads()
    this.threads.subscribe( 
        allThreads => 
        allThreads.forEach(thisThread => {
            thisThread.username = this.featuredThreadsService.getUsername(thisThread.author)
            console.log(thisThread.username)
        })
    )
} 
Run Code Online (Sandbox Code Playgroud)

出于某种原因,这会将看起来像未实现的observable的内容记录到控制台.

在此输入图像描述

我想将这些值放入属性中,threads以便我可以在我的视图中将其渲染为:

<div *ngFor="let thread of threads | async" class="thread-tile">
    ...
    {{threads.username}}
    ...
</div>
Run Code Online (Sandbox Code Playgroud)

更新:console.logfor allThreadsthisThread

在此输入图像描述

在此输入图像描述

更新:订阅了getUsername()

this.featuredThreadsService.getUsername(thisThread.author)
        .subscribe( username => console.log(username))
Run Code Online (Sandbox Code Playgroud)

结果是没有值的对象:

在此输入图像描述

car*_*ant 4

您可以基于查询成员并用用户名getFeaturedThreads替换每个线程属性中的值来编写可观察值:participants

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/switchMap';

let featuredThreadsWithUserNames = this.getFeaturedThreads()

  // Each time the getFeaturedThreads emits, switch to unsubscribe/ignore
  // any pending member queries:

  .switchMap(threads => {

    // Map the threads to the array of observables that are to be
    // joined. When the observables emit a value, update the thread.

    let memberObservables = [];
    threads.forEach(thread => {

      // Add the author:

      memberObservables.push(this.af.database
        .object(`members/${thread.author}`)
        .first()
        .do(value => { thread.author = value.username; })
      );

      // Add the participants:

      Object.keys(thread.participants).forEach(key => {
        memberObservables.push(this.af.database
          .object(`members/${key}`)
          .first()
          .do(value => { thread.participants[key] = value.username; })
        );
      });
    });

    // Join the member observables and use the result selector to
    // return the threads - which will have been updated.

    return Observable.forkJoin(...memberObservables, () => threads);
  });
Run Code Online (Sandbox Code Playgroud)

这将为您提供每次getFeaturedThreads发射时都会发射的可观察对象。但是,如果用户名发生更改,则不会重新发出。如果这很重要,请替换forkJoin为并从组成的成员可观察量中combineLatest删除该运算符。first

  • 它们是 ES6 模板文字:http://stackoverflow.com/questions/27565056/es6-template-literals-vs-concatenated-strings (2认同)