'Joining' Firebase Queries in Angularfire2

前端 未结 2 946
旧巷少年郎
旧巷少年郎 2021-01-02 20:12

Update:

The issues I was encountering with the empty value fields had to do with non-existent keys in my database, so most of the discourse here won\'t apply to yo

相关标签:
2条回答
  • 2021-01-02 20:59

    You can compose an observable based on getFeaturedThreads that queries members and replaces the values in each thread's participants property with user names:

    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);
      });
    

    This will give you an observable that emits each time getFeaturedThreads emits. However, if the user names change, it won't re-emit. If that's important, replace forkJoin with combineLatest and remove the first operator from the composed member observables.

    0 讨论(0)
  • 2021-01-02 21:05

    To solve joins on users, I wrote a service that caches the users already fetched and maps them into the referencing data with minimal code. It uses a nested map structure to do the join:

    constructor(public db: AngularFireDatabase, public users:UserProvider) {
        this.threads = db.list('threads').valueChanges().map(messages => {
          return threads.map((t:Message) => {
            t.user = users.load(t.userid);
            return m;
          });
        });
    }
    

    And the UserProvider service looks like so:

    @Injectable()
    export class UserProvider {
      db: AngularFireDatabase;
      users: Map<String, Observable<User>>;
    
      constructor(db: AngularFireDatabase) {
        this.db = db;
        this.users = new Map();
      }
    
      load(userid:string) : Observable<User> {
        if( !this.users.has(userid) ) {
          this.users.set(userid, this.db.object(`members/${userid}`).valueChanges());
        }
        return this.users.get(userid);
      }
    }
    

    There's a complete working example of the joins and all the boilerplate here

    0 讨论(0)
提交回复
热议问题