11

i'd like to join the data on init from my customers table into the projects list.

Model is like this:

  • projects

    • key
    • name: string
    • customer : customerKey
  • customers

    • key
    • name: string

Do you have an example, how i do this from angular2 component using angularfire2?

my controller looks like this:

import { Component, OnInit } from '@angular/core';
import { Project } from '../project';
import { Router } from '@angular/router';
import { FirebaseAuth } from 'angularfire2';
import { AngularFire, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2';
import { Observable } from 'rxjs';

@Component({
  moduleId: module.id,
  selector: 'app-projects',
  templateUrl: 'projects.component.html',
  styleUrls: ['projects.component.css']
})
export class ProjectsComponent implements OnInit {

  projects: FirebaseListObservable<any[]>;
  customers: FirebaseListObservable<any[]>;
  projectName: string;
  constructor(
    private router: Router,
    private af: AngularFire
  ) { };

  ngOnInit() {
    this.projects = this.af.database.list('projects');
  }

  add(projectName: string) {
    this.af.database.list('projects')
      .push({ name: projectName, id: '123' });
    this.projectName = null;
  }
}

Update

i've changed the type of this.projects to Observable from FirebaseListObservable my on ngOnInit() method looks now like this:

ngOnInit() {
this.projects = this.af.database.list(`projects`)
  .map(projects => {
    projects.map(project => {
      this.af.database.object('customer/' + project.customer + '/name')
        .subscribe(customer => {
          project.customer = customer;
        })
      return project;
    })
    return projects;
  });
}

i can now access not the name property of customer from the template inside of

<li *ngFor="let project of projects | async">

project.customer.$value
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Alex
  • 578
  • 6
  • 19
  • 2
    Can you provide more context by showing your template or better yet, creating a plnkr? – David East Jul 18 '16 at 13:15
  • Hi David, just added the model description to the post. Inside the template is nothing special -> "let project of projects | async". My problem is, how to get related customer.name from the customers table while streaming the data from the "projects" and set the this.project.customer to this value – Alex Jul 18 '16 at 17:12

1 Answers1

4

Not exactly sure how your dataset looks like, so I'm just going to write a basic example. Assuming a structure something like this:

- projects
  - key
    - name: string
    - customers
      - customerKey: boolean

- customers
  - key
    - name: string

Example data

- projects
  - projectId1
    - name: "Cool project!",
    - customers
      - customerId1: true,
      - customerId2: true
  - projectId2
    - name: "Another cool project!",
    - customers
      - customerId2: true,
      - customerId3: true

- customers
  - customerId1
    - name: "John Smith"
  - customerId2
    - name: "John Doe"
  - customerId3
    - name: "John John"

So we're storing the customers' key in every projects' customers property.

Let's say we want to list every projects, but we also want to get the customers' real name as well, not just their id. Since firebase doesn't have joins we'll have to do this manually. Here's one way to do it:

this.projects = this.af.database.list(`projects`)
  .map(projects => {
    return projects.map(project => {
      project.customers.map(customer => {
        this.af.database.list(`customers`)
          .subscribe(c => {
            customer = c;
          });
      });
      return project;
    });
  });

The inner .subscribe could be changed to a simple .map if you want to get the data asynchronously (in this case use the async pipe in the template`).

John Smith
  • 2,291
  • 4
  • 22
  • 33
  • Thank you for your reply. Exactly, customer field inside a project is just a reference to the customer record inside the customers table. Unfortunately typescript complaining about the type of FirebaseListObservable if i use your code Type 'Observable' is not assignable to type 'FirebaseListObservable'. Property '_ref' is missing in type 'Observable'. – Alex Jul 18 '16 at 16:53
  • You can change `FirebaseListObservable` type to `Observable`, it should work. – John Smith Jul 18 '16 at 17:34
  • +1 to @JohnSmith. This is a current issue with the library that we are working on, it's still in beta so be kind :) – David East Jul 18 '16 at 21:52
  • So how can we access the name-value? – Björn Kechel Sep 22 '16 at 14:07
  • 2
    And also you get `project.customers.map` is not a function error. Did anyone manage to solve this ? – Romain Bruckert Dec 26 '16 at 12:39
  • @DavidEast: does that mean that there is some show-stopper problem? Or just some suboptimal syntax/implementation/api ? – KarolDepka Jan 21 '17 at 10:59
  • 1
    Import the `map` operator. `import 'rxjs/add/operator/map';` – Clark Feb 07 '17 at 09:40
  • Won't this create a new subscription for every customer every time a project changes and never unsubscribe from old subscriptions? – rob Jun 27 '18 at 18:58