skip to Main Content

From the https://firebase.google.com/docs/firestore/query-data/queries documentation snippet, Im unable to get the results as an Observable

import { collectionGroup, query, where, getDocs } from "firebase/firestore";  

const museums = query(collectionGroup(db, 'landmarks'), where('type', '==', 'museum'));
const querySnapshot = await getDocs(museums);
querySnapshot.forEach((doc) => {
    console.log(doc.id, ' => ', doc.data());
});

So I wrote it like this:

const museums = query(
  collectionGroup(db, 'landmarks'),
  where('type', '==', 'museum')
);
const querySnapshot = await getDocs(museums);
const datas = querySnapshot.docs.map((doc) => {
  return doc.data() as Data;
});
console.log(datas);
return of(datas);

But I’m not getting results when subscribing to it or in the DOM using async pipe, but when I console.log(), there is an array of data.

component.html

{{ museums_data$ | async }}

component.ts

this.museums_data$.subscribe((datas) => console.log(datas));

2

Answers


  1. Chosen as BEST ANSWER

    I found it here: https://code.build/p/LWmSi3HfQzu5TMKPzb5p6i/angular-12-with-firebase-9, which is written for the collection. Assuming it should also work for collection groups, I tried it, and it performed as expected.

    This is a code snippet found in the link:

    collectionData<Post>(
          query<Post>(
            collection(this.afs, 'posts') as CollectionReference<Post>,
            where('published', '==', true)
          ), { idField: 'id' }
        );
    

    to:

    collectionData<Landmark>(
          query<Landmark>(
            collectionGroup(db, 'landmarks') as CollectionReference<Landmark>,
            where('type', '==', 'museum')
          ), { idField: 'id' }
        );
    

  2. At First glance code looks good but you are returning it incorrectly. Instead of mapping over you can return it directly using as Observable<Data[]>. Although I have not considered the error handling this can easily be achieved using the catchError rxjs operator.

    You can use the following technique to get the data as you want using an async pipe.

    data.service.ts :

    import { Injectable } from '@angular/core';
    import { collection, collectionData, Firestore, query, where
    } from '@angular/fire/firestore';
    import { Observable } from 'rxjs';
    import { Data } from './data';
    
    @Injectable({
      providedIn: 'root',
    })
    export class DataService {
    constructor(private db: Firestore) {}
      getData(): Observable<Data[]> {
        const ref = collection(this.db, "landmarks");
        const q = query(ref, where("type", "==", "museum"));
        const data = collectionData(q, {
          idField: 'id',
        });
        return data as Observable<Data[]>;
      }
    

    And use it like this in the corresponding component:

    app.component.ts :

    import { Component, OnInit } from '@angular/core';
    import { Observable } from 'rxjs';
    import { DataService } from './data.service';
    import { Data } from './data';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent implements OnInit {
      museums_data$!: Observable<Data[]>;
      constructor(private service: DataService) {}
      ngOnInit(): void {
        this.museums_data$ = this.service.getData();
      }
    }
    

    And

    app.component.html :

    <div *ngFor="let museum of museums_data$ | async">
      {{ museum.id }}
      //...
    </div>
    

    For more information there is this article that explains nicely.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search