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.
Instead of the map
operator, you can handle it like the following:
FriendRequest
to an Observable
.Observable
will fetch the related sender
and recipient
by combining the two Promise
(s) to one Observable
using forkJoin function (after converting each one of the Promise
(s) to an Observable
using from function)Observable
result again to a FriendRequest
object.Observable
with forkJoin
function, to return in the end Array<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(),
}))
)
)
)
)
);
}