I have an entity:
export interface FriendRequest {
sender: Profile;
recipient: Profile;
isAccepted: boolean;
dateSend: Date;
dateAccepted?: Date;
}
This is how these etities are saved in firestore:
The problem:
I want to fetch all documents from friend-request
collection and map recipient
, sender
from DocumentReference
type to Profile
object.
I tried this. This is my method which fetches all friend-request
documents:
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))
);
}
But it 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: ...,
},
]
Instead of my required output:
[
{
sender: Profile,
recipient: Profile,
isAccepted: ...,
dateSend: ...,
dateAccepted: ...,
},
{
sender: Profile,
recipient: Profile,
isAccepted: ...,
dateSend: ...,
dateAccepted: ...,
},
]
I know I should wait until promises of sender
and recipient
finish, but I dont know how to do it to return my required output.
CodePudding user response:
Instead of the map
operator, you can handle it like the following:
- Use one of the higher-order RxJS mapping operators, to map each one of the
FriendRequest
to anObservable
. - Each
Observable
will fetch the relatedsender
andrecipient
by combining the twoPromise
(s) to oneObservable
using forkJoin function (after converting each one of thePromise
(s) to anObservable
using from function) - Then map each
Observable
result again to aFriendRequest
object. - Wrap the result array of
Observable
withforkJoin
function, to return in the endArray<FriendRequest
.
Try something like the following:
// 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(),
}))
)
)
)
)
);
}