3

After looking at this answer I tried to use async/await with a firestore call but I think I am missing something.

I am trying to use Snapshot to get a collection of 'hex' documents for a hex grid. (I had valueChanges working but then realized I'm going to need metadata) I want to get the hexes, then sort them into rows, and finally return them to the component. I can see that it is returning before the snapshot and pipe actions are completed as it is empty "hexRows['test']" being console logged out as "true".

TS:

Service:

async getHexesInRows(){
    let hexRows = {test: true}
    this.hexCollection = this.db.collection('hexes', ref=> ref.orderBy('id').limit(5))

this.hexes = await this.hexCollection
  .snapshotChanges()
  .pipe(
    map(actions => actions.map( hex => {
      const data = hex.payload.doc.data()
      const uid = hex.payload.doc.id
      return {uid, ...data}
    })),
    map(data => {
      data.forEach((hex, index) => {
        let rowNum = Math.floor(index / 10)
        hexRows = {test: false}

        if(hexRows[`row${rowNum}`] == undefined){
          hexRows[`row${rowNum}`] = []
        }
        hexRows[`row${rowNum}`].push(hex)
      })
      return data
    })
  )
console.log('Rows', hexRows);
console.log('Hexes', this.hexes);

return hexRows
  }

Component

hexRows: any

  constructor(public dialog: MatDialog, public afs: FirestoreService) { }
  ngOnInit() {
    this.hexRows = this.afs.getHexesInRows()
  }
halfer
  • 19,824
  • 17
  • 99
  • 186
av0000
  • 1,917
  • 6
  • 31
  • 51

2 Answers2

2

You can't await an Observable like a Promise, instead you subscribe to the Observable where you need the data from the Observable. You usually return Observables from your Services and subscribe to them in your Components.

Return an Observable from your Service

getHexesInRows(){
  this.hexCollection = this.db.collection('hexes', ref => ref.orderBy('id').limit(5))

  return this.hexCollection
    .snapshotChanges()
    .pipe(
      map(actions => actions.map( hex => {
        const data = hex.payload.doc.data()
        const uid = hex.payload.doc.id
        return {uid, ...data}
      })),
      map(data => {
        let hexRows = {test: true}
        data.forEach((hex, index) => {
          let rowNum = Math.floor(index / 10)
          hexRows = {test: false}

          if(hexRows[`row${rowNum}`] == undefined){
            hexRows[`row${rowNum}`] = []
          }
          hexRows[`row${rowNum}`].push(hex)
        })
        return hexRows
      }),
      // tap(hexRows => this.hexRows = hexRows), // if you need the hexes in your Service but you usually shouldn't
      tap(hexRows => console.log('Rows', hexRows)) // if you want to log something in your Service
    );
}

Subscribe to the Observable in your Component

hexRows: any

constructor(public dialog: MatDialog, public afs: FirestoreService) { }

ngOnInit() {
  this.afs.getHexesInRows().subscribe(hexes => this.hexRows = hexes);
}
frido
  • 13,065
  • 5
  • 42
  • 56
  • 1
    I ended up just subscribing to hexes on my component and doing the sorting inside that subscription, so it is not exactly what you described but you definitely got me 95% of the way there lol. Just to clarify in case someone is trying to do something similar. – av0000 Feb 15 '19 at 21:45
  • @gv0000 I just noticed that I returned `data` in the last `map` instead of `hexRows` and fixed it. You should get the `hexRows` now in your Component when you subscribe and won't have to do the sorting in your Component. It's generally good practice to move the data processing logic to the Service and supply your components with clean data if you can. – frido Feb 15 '19 at 22:18
0

You cannot await an Observable, try change it to promise by adding toPromise

this.hexCollection
  .snapshotChanges()
  .pipe(
    map(actions => actions.map( hex => {
      const data = hex.payload.doc.data()
      const uid = hex.payload.doc.id
      return {uid, ...data}
    })),
    map(data => {
      data.forEach((hex, index) => {
        let rowNum = Math.floor(index / 10)
        hexRows = {test: false}

        if(hexRows[`row${rowNum}`] == undefined){
          hexRows[`row${rowNum}`] = []
        }
        hexRows[`row${rowNum}`].push(hex)
      })
      return data
    }),
    toPromise()
  )
Fan Cheung
  • 10,745
  • 3
  • 17
  • 39