75

I'm trying to retrieve my documents with id but can't figure it out.
Currently I retrieve my documents like this :

const racesCollection: AngularFirestoreCollection<Races> = this.afs.collection('races');
return racesCollection.valueChanges();

I do get my documents list perfectly, however there is no doc id with them.

How can I retrieve it for each document ?

robsiemb
  • 6,157
  • 7
  • 32
  • 46
Élyse
  • 1,351
  • 1
  • 10
  • 12

10 Answers10

70

For angular 8 and Firebase 6 you can use the option id field

      getAllDocs() {
           const ref = this.db.collection('items');
           return ref.valueChanges({idField: 'customIdName'});
      }

this adds the Id of the document on the object with a specified key (customIdName)

Ivan Tarskich
  • 1,332
  • 1
  • 12
  • 19
51

To obtain the id of the documents in a collection, you must use snapshotChanges()

    this.shirtCollection = afs.collection<Shirt>('shirts');
    // .snapshotChanges() returns a DocumentChangeAction[], which contains
    // a lot of information about "what happened" with each change. If you want to
    // get the data and the id use the map operator.
    this.shirts = this.shirtCollection.snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data() as Shirt;
        const id = a.payload.doc.id;
        return { id, ...data };
      });
    });

Documentation https://github.com/angular/angularfire2/blob/7eb3e51022c7381dfc94ffb9e12555065f060639/docs/firestore/collections.md#example

Michael Nelles
  • 5,426
  • 8
  • 41
  • 57
Luis Ruiz Figueroa
  • 2,537
  • 3
  • 18
  • 23
  • I've been trying for a while to get my code to compile. My question is this.shirts is an Observable. The example returns '{id, ...data}', which is not an object of type ShirtId. How is it being converted to a ShirtId type, it is just an object. – flobacca May 11 '18 at 17:08
  • Hey thanks for your answer, I was having the same problem. I just have one more question, do documents data are fetched as well? I mean performance wise if I just want the ids without fetching the document data, should I use this solution? – Lambasoft Feb 10 '19 at 11:58
  • @Lambasoft yes with `const data = a.payload.doc.data () as Shirt;` the object is being recovered – Luis Ruiz Figueroa Feb 11 '19 at 13:21
  • @LuisRuizFigueroa Thanks for your reply! So if I don't call doc.data() the object wont be recovered and I can use it's id normall – Lambasoft Feb 11 '19 at 13:48
  • 3
    With newer RXJS, you'll need to write snapshotChanges().pipe(map(actions => ... Hope that helps everyone looking at this post from the future :) – Cooper Scott May 27 '19 at 22:57
45

I've finally found the solution. Victor was close with the doc data.

const racesCollection: AngularFirestoreCollection<Race>;
return racesCollection.snapshotChanges().map(actions => {       
  return actions.map(a => {
    const data = a.payload.doc.data() as Race;
    data.id = a.payload.doc.id;
    return data;
  });
});

ValueChanges() doesn't include metadata, therefor we must use SnapshotChanges() when we require the document id and then map it properly as stated here https://github.com/angular/angularfire2/blob/master/docs/firestore/collections.md

Élyse
  • 1,351
  • 1
  • 10
  • 12
  • As I understand your question, do you want to get the id after saving? or do you want to get the id of each document in the collection? – Luis Ruiz Figueroa Nov 13 '17 at 21:04
  • Works. Changed it to the following to clean it up a bit ``` this.items = db.collection('games').snapshotChanges().pipe( map(actions => actions.map(a => { return { gameId: a.payload.doc.id, ...a.payload.doc.data() }; })) ); ``` – cgatian Jan 04 '19 at 02:01
38

For angular6+

    this.shirtCollection = afs.collection<Shirt>('shirts');
    this.shirts = this.shirtCollection.snapshotChanges().pipe(
        map(actions => {
        return actions.map(a => {
            const data = a.payload.doc.data() as Shirt;
            const id = a.payload.doc.id;
            return { id, ...data };
        });
        })
    );
Michael Nelles
  • 5,426
  • 8
  • 41
  • 57
phicon
  • 3,549
  • 5
  • 32
  • 62
25

doc.id gets the UID.

Combine with the rest of the data for one object like so:

Object.assign({ uid: doc.id }, doc.data())

corysimmons
  • 7,296
  • 4
  • 57
  • 65
  • This! And it's documented for [DocumentSnaphot interface](https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentSnapshot#~id) (in a collection it really is `QueryDocumentSnaphot` that extends `DocumentSnaphot`) – Sasha Davydenko Mar 13 '19 at 12:49
  • This seems like an interesting approach, however, the link doesn't offer any use example, and this answer is, let's not self-sustaining enough – KhoPhi Mar 24 '19 at 19:28
20

Since you are using angularFire, it doesn't make any sense if you are going back to default firebase methods for your implementation. AngularFire itself has the proper mechanisms implemented. Just have to use it.

valueChanges() method of angularFire provides an overload for getting the ID of each document of the collection by simply adding a object as a parameter to the method.

valueChanges({ idField: 'id' })

Here 'idField' must be same as it is. 'id' can be anything that you want your document IDs to be called.

Then the each document object on the returned array will look like this.

{
  field1 = <field1 value>,
  field2 = <field2 value>,
  ..
  id = 'whatEverTheDocumentIdWas'
}

Then you can easily get the document ID by referencing to the field that you named.

AngularFire 5.2.0

3

Can get ID before add documents in database:

var idBefore =  this.afs.createId();
console.log(idBefore);
Diego Venâncio
  • 5,698
  • 2
  • 49
  • 68
3

For document references, not collections, you need:

// when you know the 'id'

this.afs.doc(`items/${id}`)
  .snapshotChanges().pipe(
    map((doc: any) => {
      const data = doc.payload.data();
      const id = doc.payload.id;
      return { id, ...data };
    });

as .valueChanges({ idField: 'id'}); will not work here. I assume it was not implemented since generally you search for a document by the id...

Jonathan
  • 3,893
  • 5
  • 46
  • 77
  • I can get all the data and id, but that spread thing does not work. Is it because i have arrays in my (doc data) object? – O-9 Aug 13 '20 at 15:39
0

I have tried this

return this.db.collection('items').snapshotChanges().pipe(
          map(actions => {       
            return actions.map(a => {
              const data = a.payload.doc.data() as Item;
              data.id = a.payload.doc.id;
              data.$key = a.payload.doc.id;
              return data;
            });
          })
        );
Trilok Singh
  • 1,227
  • 12
  • 10
0

Sadly, in React Native environment, I couldn't find a way to import doc, to get the id. I'm working with https://rnfirebase.io/firestore/usage. It can be the same case for some less common environments relying on Firebase plugin/libraries.

In that case console.log(documentSnapshot.ref); will return you what you can find below.

enter image description here

as you could see, while working with the raw response, it can be accessed via documentSnapshot.ref._documentPath._parts[1]. documentSnapshot is of course part of querySnapshot.

Daniel Danielecki
  • 8,508
  • 6
  • 68
  • 94