AngularFire2 - Joining members and users

326 Views Asked by At

I am trying to list users conversations in an AngularFire2 app, which strucutre is the following:

chats

"chat1": {
  title: "First chat",
  lastMessage: "Hello world",
  members: {
    "user1": true,
    "user2": true,
  }
}

users

"user1": {
  name: "Ben",
  surname: "Bennsay"
}
"user2": {...}

I am trying to map and list chats in a way that i can easily display the chats participants names bellow the last message.

Question 1: This example differs a little bit from then official recommendation but i feel it would still be valid and scalable. Am i right ?

Question 2: How to actually join members and users to have a users array in my chats list ?

Here is what i have so far.

// retrieve chats "user1" participates in
this.afChatsRef = this.af.database.list(this.datastore(), {
  query: {
    orderByChild: "/members/user1", // by user id in members
    equalTo: true,
  }
}).map(chats => {
   chats.map(chat => {
        // HMMM? WHAT TO DO HERE ?
   });
   return chats;
});

Thanks, in advance.

UPDATE i have also tried the following, which does not seem quite right (and i cannot access user properties).

 this.af.database.list(this.datastore()).map(chats => {

            chats.map(chat => {
                // chat.users = [];

                for (var key in chat.members) {
                    this.af.database.object("/users/" + key).subscribe(user => {
                        chat.members[key] = user;
                    });
                }

                return chat;
            });

            console.log(chats);
            return chats;
        });
1

There are 1 best solutions below

0
On

You want to return the nested map and fetch the users inside of that. Something like this;

// retrieve chats "user1" participates in
this.afChatsRef = this.af.database.list(...).map(chats => {
   // Note the return!
   return chats.map(chat => {
        // Avoid side effects by storing members separate from the keys
        chat.memberData = {};
        // Iterate keys and download members
        Object.keys(chat.members||{}).forEach(uid => {
            // `users` represents a service to cache and load users on demand
            chat.memberData[uid] = users.load(uid);
        });
   });
   return chats;
});

Here's a good way to create the users service with caching:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { AngularFireDatabase } from 'angularfire2/database';

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

export interface User {
  name:string;
  nick:string;
}

And here is a working example of async joins in AngularFire2.