转换RxJS可观察

时间:2018-10-19 10:25:27

标签: javascript angular rxjs

我使用angularFirestore在Firebase上进行查询,并希望使用DocumentReference联接来自多个文档的数据。

管道中的第一个运算符映射返回IOrderModelTable数组,第二个运算符,即switchMap遍历数组,对每个元素使用每个元素中包含的ID来查询其他表中的数据。

问题在于,由于带地图的操作符,我在swithMap中获得了一个可观察的数组。如何获取IOrderModelTable的数组,然后返回该数组的可观察值。

代码是:

getDataTableOperatorsFromDB(): Observable<IOrderModelTable[]> {
  const observable = this.tableOperatorsCollectionsRef.snapshotChanges().pipe(
    map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data() as IOrdersModelDatabase;
        const id = a.payload.doc.id;

        data.ot = id;
        return data;
      });
    }),
    switchMap(data => {
      const result = data.map(element => {
        return this.afs.collection('Orders/').doc(element.orderNumberReference.id).valueChanges().pipe(map(order => {
          return {
            otNumber: element.ot,
            clientName: '',
            clientReference: order.clientReference,
            id: element.orderNumberReference,
          };
        }));
      });

      // Result must be an IOrderModelTable[] but is a Observable<IOrderModelTable>[]

      return of(result);
    })
  );

2 个答案:

答案 0 :(得分:1)

您可以使用to Array运算符将流转换为数组,但要确保流将结束。 诀窍是选择正确的流。

对于您的问题,自然源将是您的第一个电话收到的列表。用一种示意性的方式,我可以得到一个id列表,然后将其转换为增强信息列表:

第一个输入...snapshopChanges()

  

---- [[A,B,C] ------>

每个元素都通过...valueChanges()进行转换:

  

-------呼叫A ------------- DataA -------->

     

-------呼叫B ------------------------ DataB ----->

     

-------呼叫C -------------------- DataC ----->

然后使用toArray()简化为:

  

------------------------------------------------ [ DataA,DataC,DataB] -------->

代码

getDataTableOperatorsFromDB(): Observable<IOrderModelTable[]> { {
  return this.tableOperatorsCollectionsRef.snapshotChanges()
    .pipe(
      map(actions => {
        from(data).pipe(
          map(action => {
            const data = a.payload.doc.data() as IOrdersModelDatabase;
            const id = a.payload.doc.id;
            data.ot = id;
            return data;
          }),
          mergeMap(element => {
            return this.afs.collection('Orders/').doc(element.orderNumberReference.id).valueChanges().pipe(
              map(order => {
                return {
                  otNumber: element.ot,
                  clientName: '',
                  clientReference: order.clientReference,
                  id: element.orderNumberReference,
                };
              })
            );
          }),
          toArray()
        );

      })
    )
}

重要提示:我将switchMap替换为mergeMap,否则一些信息可能会被丢弃。

答案 1 :(得分:1)

@madjaoue 没错,在这种情况下,mergeMap是正确的运算符,因为对于每个发出的事件,使用switchMap都会破坏内部的可观察对象,因此在订阅中,您只会得到发出的最终事件,即最后一行。这种可观察的生命周期长,从不完整,因此还请使用运算符take来指定包含文档列表的数组的操作长度。

非常感谢您的帮助。 :D

getDataTableOperatorsFromDB(): Observable<IOrderModelTable[]> {
    const observable = this.tableOperatorsCollectionsRef.snapshotChanges().pipe(
      switchMap(actions => {
        return from(actions).pipe(
          mergeMap(action => {
            console.log(action);
            const data = action.payload.doc.data() as IOrdersModelDatabase;
            const otNumber = action.payload.doc.id;
            return this.afs.collection('Orders/').doc(data.orderNumberReference.id).valueChanges().pipe(map(order => {
              return {
                otNumber: otNumber,
                clientName: '',
                clientReference: order.clientReference,
                id: data.orderNumberReference,
              };
            }));
          }),
          mergeMap(order => {
            console.log(order);
            return this.afs.collection('Clients/').doc(order.clientReference.id).valueChanges().pipe(map(client => {
              return {
                otNumber: order.otNumber,
                clientName: client.name,
                clientReference: order.clientReference,
                id: order.id,
              };
            }));
          }),
          take(actions.length),
          toArray(),
          tap(console.log),
        );
      }),