Issue
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.
Solution
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
FriendRequestto anObservable. - Each
Observablewill fetch the relatedsenderandrecipientby combining the twoPromise(s) to oneObservableusing forkJoin function (after converting each one of thePromise(s) to anObservableusing from function) - Then map each
Observableresult again to aFriendRequestobject. - Wrap the result array of
ObservablewithforkJoinfunction, 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(),
}))
)
)
)
)
);
}
Answered By - Amer

0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.