Angular: Navigating through two levels of fetched data from Firebase

I'm currently working on parsing retrieved data from Firebase within an Angular (Typescript) project.

The structure of my JSON data in Firebase resembles the following:

"customer" : {
  "customerId1" : {
    "documents" : {
      "documentId1" : {
        "documentName" : "file1.pdf",
        "documentUrl" : "someUrl1"
      },
      "documentId2" : {
        "documentName" : "file2.pdf",
        "documentUrl" : "someUrl2"
      }
    },
    "email" : "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8deef8fef9e2e0e8f9bccde8e0ece4e1a3eee2e0">[email protected]</a>",
    "name" : "Customer 1",
  },
  "customerId2" : {
    "documents" : {
      "documentId3" : {
        "documentName" : "file3.pdf",
        "documentUrl" : "someUrl3"
      },
      "documentId4" : {
        "documentName" : "file4.pdf",
        "documentUrl" : "someUrl4"
      }
    },
    "email" : "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="83e0f6f0f7eceee6f1b1c3e6eee2eaefade0ecee">[email protected]</a>",
    "name" : "Customer 2",
  }
}

Each customer entry includes three main properties at the first level: documents, email, and name. The documents property further contains nested properties such as documentName and documentUrl. To parse this customer data, I have implemented the following code snippet.

customer.component.ts:

...
export class CustomerComponent implements OnInit {

  customerObservable: Observable<any[]>;
  customerList: Customer[];

  constructor(db: AngularFireDatabase) {
    // Listening to customer data
    this.customerObservable.subscribe(data => {
      this.customerList = data;
    });
  }

}
...

This code allows me to retrieve and loop through the data using the ngFor directive in HTML with the help of the customerList variable. Now, my question is how can I accomplish something like the following?

// Variable containing an array of arrays representing customers' document collections
documentList: Document[][];
// Alternatively,
// Variable storing individual customer documents
customerDocuments: Document[];

// Here's what the Document model entails
export class Document {
    public documentName: string;
    public documentUrl: string;
}

Thank you for your assistance.

Answer №1

Below is the code snippet for the service:

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

@Injectable()
export class FirebaseService {
  constructor(private angularFireDatabase: AngularFireDatabase) {}

  onGetUserDocuments(customer: string) {
    return this.angularFireDatabase.list(`customer/${customer}/documents`).valueChanges()
  }

  onGetUsersDocuments(){
    return this.angularFireDatabase.list('customer').snapshotChanges()
      .map((changes)=>{
        return changes.map((data) => {
          return data.payload.key
        });
      })
      .switchMap((usersId: string[]) => {
        return Observable.combineLatest( usersId.map((u)=>{
          return this.onGetUserDocuments(u);
        }))
      })
  }
}

You can then call the service in your component like so:

import {Component, OnInit} from '@angular/core'; 
import {FirebaseService} from '../services/firebase.service';
@Component({
  selector: 'new',
  templateUrl: './new.component.html',
  styleUrls: ['./new.component.css']
})
export class NewComponent implements OnInit {
  constructor(private firebaseService: FirebaseService) {}

  ngOnInit(){
    this.firebaseService.onGetUsersDocuments().subscribe(data => console.log(data));
  }
}

This will result in:

[Array(2), Array(2)]
0: Array(2)
  0: {documentName: "file1.pdf", documentUrl: "someUrl1"}
  1: {documentName: "file2.pdf", documentUrl: "someUrl2"}
1: Array(2)
  0: {documentName: "file3.pdf", documentUrl: "someUrl3"}
  1: {documentName: "file4.pdf", documentUrl: "someUrl4"}

To display the data, you can do the following:

<div *ngFor="let docs of data">
  <div *ngFor="let doc of docs">
    <p>File Name: {{doc.documentName}}</p>
    <p>File URL: {{doc.documentUrl}}</p>
  </div>
</div>

If you require any clarifications or have questions, feel free to reach out.

P.S. It's important to note that nesting like this is not recommended by Firebase; you should flatten your data structure. More information can be found in the new documentation and the old documentation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to Showcase Images in an Ionic 2 App Using HTML Content

This amazing app was built with Ionic 2 technology. It leverages a REST API to retrieve data in JSON format. Interestingly, one of the fields sent from the server is HTML content. <div [innerHTML]="'<p>' + eventMoreDetails.DescriptionHt ...

Utilizing OverlappingMarkerSpidifier in conjunction with sebm-angular2-google-map

I'm currently integrating OverlappingMarkerSpidifier using SebM Angular 2 Google Maps on angular2 2.0.0. After successfully loading the google maps API with the GoogleMapsAPIWrapper imported from the sebm module, I am running into an issue when execu ...

The Google Books API initially displays only 10 results. To ensure that all results are shown, we can implement iteration to increment the startIndex until all results have

function bookSearch() { var search = document.getElementById('search').value document.getElementById('results').innerHTML = "" console.log(search) var startIndex = I have a requirement to continuously make Ajax calls ...

Encountered a hiccup during the installation of ssh2-sftp-client on Next.js

I'm looking for a way to save uploaded files in my domain's storage using SFTP. I came across the multer-sftp package, but when I attempted to run the command yarn add multer-sftp ssh2-sftp-client, I encountered a strange error with the second pa ...

What is the best way to modify an existing object in an Observable Array in Angular?

As I work on my Ionic 5 / Angular application, a challenge arises when attempting to update a Conversation object within the existing array of Conversation: private _conversations = new BehaviorSubject<Conversation[]>([ new Conversation( & ...

What is causing this issue in TypeScript version 4.8?

After updating to TypeScript 4.8 in VSCode, I have encountered an error in one of my React projects that was not present before. Strangely, this error does not prevent the code from compiling successfully when building the project. It's challenging to ...

Utilizing Typescript to Transfer Data from Child to Parent in React

Attempting to pass data from a Child Component to a Parent component using Typescript can be challenging. While there are numerous resources available, not all of them delve into the TypeScript aspect. One question that arises is how the ProductType event ...

Working with JSON data in postgresql

I am currently working with a postgres database that houses student information such as their names, passwords, and the groups they belong to. This data is stored in JSON format. I am attempting to extract specific data points for each category, which are: ...

Incorrectly calling Asset URL in a single spa micro front-end

Currently, I am utilizing the single-spa library to implement micro front-end functionality. My challenge lies in using assets within my pages as the generated URLs for fetching these assets are incorrect. For example, when attempting to use an informati ...

Customize the font style of Angular mat expansion panel

Is there a way to customize the font style for the panel header, title, and content in mat-expansion? ...

Serializing a Guava Optional<Integer> to a string with the help of Jackson

My value object includes a field of type Optional<Integer>. I need this field to be serialized as a string, but the presence of Optional is causing issues. Here is the relevant class: public class Person { private com.google.common.base.Optiona ...

leveraging external libraries with angular

Is there a way to integrate third-party libraries into Angular 4? Typically, I follow the code snippet below: <html> <head> <title>Bootstrap CDN Simple Example</title> <link href="//netdna.bootstrapcdn.com/ ...

What advantages does ViewContainerRef offer compared to *ngif?

Instead of just using *ngIf to conditionally include my-awesome-component, I could also use ViewContainerRef. However, I'm not sure what makes it so special compared to *ngif. Can someone please point out the advantages and disadvantages of both metho ...

Error in syntax: An unexpected token was encountered during an AJAX request

I am currently working on a project that involves looping through multiple JSON files within a directory called "trips" and extracting data from each file to display on the front end of the website. However, I'm encountering a persistent error message ...

Error message TS2339 in Typescript: The property '__super__' is not found on the type '($element: any, options: any) => any'

Having trouble with Javascript code inside typescript. $.fn.select2.amd.require([ 'select2/data/array', 'select2/utils' ], function (ArrayData, Utils) { /* tslint:disable */ function CustomData ($element, opti ...

Limit the frequency of function calls in Typescript

Update: After some research, I've learned that throttle has the capability to drop excess function invocations, making it unsuitable for my needs. I am still seeking an idiomatic solution to process every item in a queue at an appropriate pace without ...

Assistance needed in managing JSON replies

I'm currently grappling with the concept of using json. Can someone assist me in deciphering how to handle this response? Here is my query: $.ajax({ url: s7query, dataType: 'jsonp', success: function(){ // What's the best way to work w ...

Unifying and organizing query output from various models - the Rails approach

I have a JSON-rendering controller with the following code: class AppLaunchDataController < ApiController def index service_types = [] vendors = [] tariffs = [] fields = [] vendors_hash = {} service_t ...

Maintaining database consistency for multiple clients making simultaneous requests in Postgres with Typeorm and Express

My backend app is being built using Express, Typescript, Typeorm, and Postgres. Let's consider a table named Restaurant with columns: restaurant_id order (Integer) quota (Integer) The aim is to set an upper limit on the number of orders a restaura ...

Can you explain the functionality of `property IN array` in the TypeORM query builder?

I'm looking to filter a list of entity ids using query builder in an efficient way. Here's the code snippet I have: await this._productRepo .createQueryBuilder('Product') .where('Product.id IN (:...ids)', { ids: [1, 2, 3, 4] ...