Jonathan
Jonathan

Reputation: 9151

Firestore only returns last doc

I'm using AngularFirestore and NgRx and I have a problem that when I have several requests to the same method only the last one gets fulfilled. How can I fix this?

DB method

// Using: import { AngularFirestore } from '@angular/fire/firestore';
getUnit(unitId: string): Observable<Unit> {  
  const unit$ = this.afs
    .collection<Unit>(constants.dbCollections.units)
    .doc(unitId)
    .snapshotChanges()
    .pipe(map((x) => x.payload.data()));

  return unit$;
}

This method gets called correctly with multiple IDs.

Effect

loadUnit = createEffect(() =>
  this.actions$.pipe(
    ofType(unitActions.loadUnit),
    switchMap(({ unitId }) => {
      console.log('EFFECT CALL: ' + unitId);
      return this.dbService.getUnit(unitId).pipe(
        map((unit) => {
          console.log('EFFECT MAP: ID' + unitId, unit);
          return unitActions.unitLoaded({ unit });
        })
      );
    })
  )
);

This logs:

EFFECT CALL: re_demo_d4_c01_u01
EFFECT CALL: re_demo_d4_c01_u02
EFFECT CALL: re_demo_d4_c01_u03
EFFECT CALL: re_demo_d4_c01_u04
EFFECT CALL: re_demo_d4_c01_u05
EFFECT MAP: IDre_demo_d4_c01_u05 {thumbnail: "[url]", title: "10% 25% 50% 100%", introduction: Array(4), id: "re_demo_d4_c01_u05", name: "Procenten en breuken", …}
EFFECT MAP: IDre_demo_d4_c01_u05 {thumbnail: "[url]", title: "10% 25% 50% 100%", introduction: Array(4), id: "re_demo_d4_c01_u05", name: "Procenten en breuken", …}

The fact that MAP is triggered twice is something else that I don't really understand but can be solved by piping sharedReplay in the DB method. It doesn't seem like the problem at hand though.

How do I get all docs?

I'm using:

"@angular/fire": "^6.1.4",
"firebase": "^7.24.0",
"rxjs": "^6.6.3",
"@ngrx/core": "^1.2.0",
"@ngrx/effects": "^10.1.2",

Upvotes: 0

Views: 117

Answers (1)

Jonathan
Jonathan

Reputation: 9151

It was a mistake with higher order observable mapping. In my effect I was using switchMap which cancelled all uncompleted observables. What I wanted was all observables completing (in parallel) which is accomplished using mergeMap

mergeMap(({ unitId }) =>
        this.dbService
          .getUnit(unitId)
          .pipe(map((unit) => unitActions.unitLoaded({ unit })))

Detailed explanation found here: https://blog.angular-university.io/rxjs-higher-order-mapping/

The other weird thing were the inner observable was emitting twice was resolved by adding get on the doc.

.collection<Unit>(constants.dbCollections.units)
      .doc(unitId)
      .get()

Upvotes: 1

Related Questions