Rob
Rob

Reputation: 718

retrieve subcollections in cloud firestore

Let's have a biz model defined like this

export inteface Item {
    id: string;
    name: string;
}

export interface Container {
    id: string;
    items: Item[];
}

In Cloud Firestore we have collection /containers and each container contains collection /items with documents. Each document has field name. So the structure inside Cloud Firestore copies our biz model.

Now I'd like to retrieve specific container with its collection of items.

getContainer(idIn: string) {
  const document: AngularFirestoreDocument<Container> = this.afs.doc('containers/' + idIn);
  const document$: Observable<Container> = document.snapshotChanges().map(a => {
      const data = a.payload.data() as Container;
      const id = a.payload.id;
      return this.getItems(idIn).map( item => {
        return {id, ...data, items: item};
      });
    });
  return document$;
}

getItems(id: string) {
  const collection: AngularFirestoreCollection<Item> = this.afs.collection('containers/' + id + '/items');

  return collection.snapshotChanges().map(actions => {
    return actions.map(a => {
      const data = a.payload.doc.data() as Item;
      const id = a.payload.doc.id;
      return {id, ...data};
    });
  });
}

But i keep getting this error about missing id on returning Observable. Compiling with typescript 2.6.2.

error TS2322: Type 'Observable<Observable<{ items: { 'id': string;  'item': string; }[]; 'id': string...' is not assignable to type  'Observable<Container>'.
 Type 'Observable<{ items: { 'id': string; 'item': string; }[]; 'id': string...' is not assignable to type 'Container'.
 Property ''id'' is missing in type 'Observable<{ items: { 'id': string; 'item': string; }[]; 'id': string...'.

Could anyone point out what i am doing wrong?

Upvotes: 0

Views: 1164

Answers (2)

Jobel
Jobel

Reputation: 643

I am reading nested collections in Firestore to populate in my case an Expansion widget. See my solution in https://stackoverflow.com/a/51057195/5013735

The trick is in to create a structure like:

  List<Widget> _getChildren() {
    List<Widget> children = [];
    documents.forEach((doc) {
      children.add(
        ProjectsExpansionTile(
          name: doc['name'],
          projectKey: doc.documentID,
          firestore: firestore,
        ),
      );
    });
    return children;
  }

Upvotes: 0

Hareesh
Hareesh

Reputation: 6900

It looks to me your return data is not same as the Interface modal. You only specified id and items fields in the interface, so it will be

  const data = a.payload.data() as Container;
  const id = a.payload.id;
  let items=[];
  this.getItems(idIn).valueChanges().subscribe(res=>{
      res.forEach(item=>{
        items.push(item);
      })
    });
  return {id:id, items: items};

Upvotes: 1

Related Questions