AngularFire2: Realtime Database: how to get key and value
Asked Answered
D

7

12

I use AngularFire2 to get data from Firebase Database (realtime).

What I have done:

  • Firebase Database

{ “class” : { “student” : { “Tom” : “male”, “Mary” : “female”, “Peter” : “male”, “Laura” : “female” }, "numberOfStudent” : 10 } }

  • app.component.ts

    import { AngularFireDatabase } from 'angularfire2/database';
    import { Observable } from 'rxjs/Observable';
    
    ...
    export class AppComponent {
    
       class: Observable<any>;
       students: Observable<any[]>;
    
    constructor(private db: AngularFireDatabase) {
       this.class = db.object(‘class’).valueChanges();
       this.students = db.list(‘class/student’).snapshotChanges();
     }
    
    } 
    
  • app.component.html:

<h2>Class size: {{ (class | async)?.numberOfStudent }}</h2>
<ul>
  <li *ngFor="let i of students | async">
    {{i.key}} : {{i.value}}
  </li>
</ul>

What happened:

Class size: 10

Tom :

Mary :

Peter :

Laura :

It doesn't return the value of list.

Any suggestion is appreciated.

Dottie answered 5/10, 2017 at 13:56 Comment(7)
any errors? for your key and value do {{ i?.key }} : {{ i?.value }}, the safe operator ? will stop any errors for the data not being there yetPolky
@FussinHussin, no error, it worked with key, but not value, just empty values.Dottie
can you log those values in your .ts component? does the data come through?Polky
The data shud come through, because I can get the key. Just don't know if my code to get the value is correctDottie
yes, but you should log the data just to make sure, can't hurtPolky
By the way, how to log the data? :-) I tried, but error, because it's realtime databaseDottie
....In your component.ts file, console.log(this.class, this.students)Polky
P
15

UPD

with new Angular 6 and RxJS 6 you'll do this:

import { map } from 'rxjs/operators';
// ...
return this.fb.list(`/path/to/list`)
  .snapshotChanges()
  .pipe(map(items => { .            // <== new way of chaining
    return items.map(a => {
      const data = a.payload.val();
      const key = a.payload.key;
      return {key, data};           // or {key, ...data} in case data is Obj
    });
  }));
Prayer answered 7/6, 2018 at 6:49 Comment(1)
Property 'subscribe' does not exist on type '() => Observable<{ key: string; }[]>'. I cant subscribe to this return. any idea?Bomber
P
7

AngularFire2 library has gone through some breaking changes since @rickdroio's answer. The following is an updated version of the solution:

afs.collection<Shirt>('class/student').snapshotChanges().map(actions => {
  return actions.map(a => {
    const data = a.payload.val();
    const id = a.payload.id;
    return { id, ...data };
  });
});
Picot answered 7/2, 2018 at 10:25 Comment(2)
getting this error ERROR TypeError: this.fb.list(...).snapshotChanges(...).map is not a function at ... I assume it's because of the RxJS 6 version. Does anyone know how to fix it?Prayer
see response belowPrayer
D
6

I managed to get the key and value of list. Just follow some tips below:

  • Make sure using snapshotChanges()

<li *ngFor="let i of seats | async">
    {{i.key}} : {{i.payload.val()}}
</li>

It worked for me, but I am still opening to receive more best practices

Dottie answered 6/10, 2017 at 9:5 Comment(0)
E
2

According to guideline available on https://github.com/angular/angularfire2/blob/master/docs/firestore/collections.md you could do something like that:

afs.collection<Shirt>('class/student').snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data();
        const id = a.payload.doc.id;
        return { id, ...data };
      });
    });

It will return a similar array like previous Firebase db.

Exhaust answered 6/10, 2017 at 12:57 Comment(0)
P
1

your problem is your JSON object students is not an array, and you are trying to loop through it.

    "student" : { “Tom” : “male”, “Mary” : “female”, “Peter” : “male”, “Laura” :
“female” }, "numberOfStudent” : 10 }

you need to make your students a list of objects in order to loop through them, like so:

   "student" :
[ { "name" : "Tom", "sex" : male}, {"name" : "Mary, "sex" : "female" }, ... ]

the loop through let i of student | async and access the name and sex i?.name, i?.sex

Polky answered 5/10, 2017 at 14:32 Comment(2)
I got your point, but this JSON is generated from Firebase Database. I handle data by using AngularFire2, not handle data thru the JSON.Dottie
I understand, but the way your data is formatted is a bad practice, best practice would be to put it into a list of objects formatPolky
P
1

With Angular 6
Breakdown:

  1. I created a Map to store the key/values for future queries.

  2. Fetched the values and added them to the previously created Map

  3. Created two helper methods to get the key or the value separately.

todosKeyValues: Map<string, Todo> = new Map();

constructor(private databaseFB: AngularFireDatabase) {
    this.fetchKeyValues();
 }

private fetchKeyValues() {
    this.databaseFB.list('/').snapshotChanges().subscribe(actions => {
      actions.forEach(action => {
        const value = action.payload.val();
        const id = action.payload.key;
        this.todosKeyValues.set(id, value);
      });
    });
  }


 private getKey(id: number): string {
 const foundEntry = Array.from(this.todosKeyValues.entries())
    .filter(entry =>entry[1].id === id).pop();
   return foundEntry ? foundEntry[0] : undefined;
  }

  private getTodo(id: number): Todo {
    const foundEntry = Array.from(this.todosKeyValues.entries())
    .filter(entry => entry[1].id === id).pop();
      //index 0 is the key, index 1 is the value
    return foundEntry ? foundEntry[1] : undefined;
  }
  ...
Peake answered 21/7, 2018 at 20:11 Comment(0)
W
0

I tried all of these above, none of this worked as of Angular 6 this worked for me

   const m = this.firestore.collection("class/student").snapshotChanges();
    m.subscribe(res =>{
      console.log(res)
      res.forEach(res => {
        const value = res.payload.doc.data();
        const id = res.payload.doc.id;
        console.log(value," ",id)
      });
    })

A lot of methods of angular fire went obsolete. The key lied in vs code suggestion, in future if this doesn't work you would have to explore the provided similarly. For now

res.payload.doc.data()
res.payload.id

Would work.

Wolf answered 5/4, 2020 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.