如何订阅和退订单个Firestore查询?

时间:2020-02-20 01:55:40

标签: ngrx

我正在尝试通过使用两个操作来修改使我可以启动和停止多个Firestore查询的效果。目前,该效果允许我通过侦听效果中的两个独立操作来启动和停止单个Firestore查询。当发生停止动作时,我只是使用switchMap切换到一个空的可观察对象。这样就可以了。

@Effect()
startStopQuery$ = this.actions$.pipe(
  ofType(
    ActionTypes.START,
    ActionTypes.STOP
  ),
  switchMap(action => {
    if (action.type === ActionTypes.STOP) {
      return of([]);
    } else {
      return this.afs.collection('collection', ref => {
        return ref.where('field', '==', 'x');
      }).stateChanges();
    }
  }),
  mergeMap(actions => actions),
  map(action => {
    return {
      type: `[Collection] ${action.type}`,
      payload: { id: action.payload.doc.id, ...action.payload.doc.data() }
    };
  })
);

我实际上想要做的是让多个查询持续进行,我可以通过相同的两个动作来开始和停止,但是这取决于动作有效负载。每次执行新查询时,对其进行修改时,最后一个查询将停止工作。我认为这是因为switchMap运算符从我观察到的上一个查询切换开了。这是我想出的最好的方法:

@Effect()
startStopQueryById$ = this.actions$.pipe(
  ofType(
    ActionTypes.START_BY_ID,
    ActionTypes.STOP_BY_ID
  ),
  switchMap(action => {
    if (action.type === ActionTypes.STOP_BY_ID) {
      return of([]);
    } else {
      return this.afs.collection('collection', ref => {
        return ref.where('field', '==', action.id);
      }).stateChanges();
    }
  }),
  mergeMap(actions => actions),
  map(action => {
    return {
      type: `[Collection] ${action.type}`,
      payload: { id: action.payload.doc.id, ...action.payload.doc.data() }
    };
  })
);

正如我所说,我认为问题是switchMap运算符。但这也是我首先要使“停止”工作所依赖的。我似乎还无法提出另一种解决方案,因为我还不太熟悉这种风格。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

我想出了一个解决方案。我制作了一个将ID映射到firestore statechanges可观察对象的对象。在开始动作中,我使侦听器并将其添加到对象。我确保通过用相应的停止操作用管道takeUntil来取消订阅。它返回对象中所有可观察对象的merge,我像以前一样傻傻地做。我还有一个单独的作用,由stop动作触发,以从对象中移除可观察对象。看起来像这样:

queriesById: {[id: string]: Observable<DocumentChangeAction<Element>[]>} = {};
@Effect()
startQuery$ = this.actions$.pipe(
  ofType(ActionTypes.START_BY_ID),
  switchMap(action => {
    this.queriesByPlay[action.pid] = this.afs.collection<Element>('requests', ref => {
      return ref.where('field', '==', action.id);
    }).stateChanges().pipe(
      takeUntil(
        this.actions$.pipe(
          ofType(ActionTypes.STOP_BY_ID),
          filter(cancelAction => action.id === cancelAction.id),
        )
      )
    );
    return merge(
      Object.values(this.queriesByPlay)
    );
  }),
  mergeMap(actions => actions),
  mergeMap(actions => actions),
  map(action => {
    return {
      type: `[Collection] ${action.type}`,
      payload: { id: action.payload.doc.id, ...action.payload.doc.data() }
    };
  })
);

Effect({dispatch: false})
stopQuery$ = this.actions$.pipe(
  ofType(ActionTypes.STOP_BY_ID),
  map(action => delete this.queriesByPlay[action.id]),
);

这似乎可行,除了难以理解的麻烦之外,没有任何问题。