Angular Firestore:在获取集合时将 DocumentReference 属性映射到对象

Angular Firestore: Map DocumentReference attribute to object while fetching collection

我有一个实体:

export interface FriendRequest {
    sender: Profile;
    recipient: Profile;
    isAccepted: boolean;
    dateSend: Date;
    dateAccepted?: Date;
}

这就是这些实体在 firestore 中的保存方式:

问题: 我想从 friend-request 集合中获取所有文档,并将 recipientsenderDocumentReference 类型映射到 Profile 对象。

我试过了。这是我获取所有 friend-request 文档的方法:

listenOnReceivedFriendRequests(profileId: string): Observable<Array<FriendRequest>> {
        const myProfileReference = this.$db.doc(`${PROFILE_COLLECTION}/${profileId}`);

        return this.$db.collection<FriendRequest>(
            FRIEND_REQUEST_COLLECTION,
            ref => ref.where('recipient', '==', myProfileReference.ref)
        )
            .valueChanges()
            .pipe(
                map((friendRequests) => {
                    return friendRequests.map((friendRequest) => {

                        // This is the place where it goes wrong I guess
                        return {
                            ...friendRequest,
                            sender: friendRequest.sender.get().then((senderDoc) => friendRequest.sender = senderDoc.data()),
                            recipient: friendRequest.recipient.get().then((senderDoc) => friendRequest.recipient = senderDoc.data())
                        };
                    });

                }),
                tap(result => console.log(result))
            );
    }

但它 returns:

[
    {
        sender: ZoneAwarePromise,       // <-- Instead of Profile object
        recipient: ZoneAwarePromise,    // <-- Instead of Profile object
        isAccepted: ...,
        dateSend: ...,
        dateAccepted: ...,
    },
    {
        sender: ZoneAwarePromise,       // <-- Instead of Profile object
        recipient: ZoneAwarePromise,    // <-- Instead of Profile object
        isAccepted: ...,
        dateSend: ...,
        dateAccepted: ...,
    },
]

而不是我的要求的输出:

[
    {
        sender: Profile,
        recipient: Profile,
        isAccepted: ...,
        dateSend: ...,
        dateAccepted: ...,
    },
    {
        sender: Profile,
        recipient: Profile,
        isAccepted: ...,
        dateSend: ...,
        dateAccepted: ...,
    },
]

我知道我应该等到 senderrecipient 的承诺完成,但我不知道如何做到 return 我需要的输出。

而不是 map 运算符,您可以像下面这样处理它:

  • 使用 higher-order RxJS mapping operators 之一,将每个 FriendRequest 映射到 Observable
  • 每个 Observable 将通过使用 [=27= 将两个 Promise(s) 合并为一个 Observable 来获取相关的 senderrecipient ]函数)
  • 然后将每个 Observable 结果再次映射到 FriendRequest 对象。
  • Observable的结果数组用forkJoin函数包装起来,最后变成returnArray<FriendRequest.

尝试如下操作:

// import { forkJoin, from, Observable } from 'rxjs';
// import { map, mergeMap } from 'rxjs/operators';

listenOnReceivedFriendRequests(
  profileId: string
): Observable<Array<FriendRequest>> {
  const myProfileReference = this.$db.doc(
    `${PROFILE_COLLECTION}/${profileId}`
  );

  return this.$db
    .collection<FriendRequest>(FRIEND_REQUEST_COLLECTION, (ref) =>
      ref.where('recipient', '==', myProfileReference.ref)
    )
    .valueChanges()
    .pipe(
      mergeMap((friendRequests: Array<FriendRequest>) =>
        // forkJoin returns Observable<Array<FriendRequest>>
        forkJoin(
          // map each item to an Observable<FriendRequest>, after resolving the related profiles.
          friendRequests.map((friendRequest) =>
            forkJoin({
              senderDoc: from(friendRequest.sender.get()),
              recipientDoc: from(friendRequest.recipient.get()),
            }).pipe(
              map(({ senderDoc, recipientDoc }) => ({
                ...friendRequest,
                sender: senderDoc.data(),
                recipient: recipientDoc.data(),
              }))
            )
          )
        )
      )
    );
}