angular - Kan jag både mappa till Observables, som pipas in i mergeMap -> forkJoin OCH skicka ett objekt till nedströms i RxJs?
Jag vet, det är en ganska komplicerad fråga, men jag är verkligen vilse i RxJs-dokumentationen ...
Jag har en Angular-applikation, och jag använder OpenLibrary API för att skapa en hemläxa. Jag har en tjänst, som heter SearchService, som använder /search-endpointen. Problemet är att denna endpoint returnerar dokument som inte är i önskat format, så för varje returnerat dokument måste jag fråga det faktiska objektet från en annan endpoint, en i taget, eftersom batchförfrågningar verkar omöjliga för tillfället (servern returnerar bara HTTP 500).
Min lösning, som för närvarande fungerar, är som följer:
- Fråga
/search-endpointen med AngularsHttpClient, denna funktion returnerar enObservable<AuthorSearchResponse> - Skicka detta till en RxJs
map-operator, filtrera bort dåliga värden och mappa resultatdokumenten (var och en av dem) till enObservable<Author>, som produceras av en annan tjänst (this.authorService.getAuthorById(id)använder ocksåHttpClientför att fråga och transformera en given författare efter ID) - Skicka denna
Observable<Author>[]till enmergeMapRxJs-operator, som använderforkJoin-operatorn. Detta kommer att producera den önskadeAuthor[]-arrayen - Pipa detta resultat till en
map-operator, som omvandlar denna array till det önskadeQueryResult<Author>-objektet, som innehåller en array avAuthor-objekt, samt det aktuella antalet returnerade objekt, och det bör innehålla det totala antalet sökresultat.
Så här ser min kod ut:
Gränssnittet AuthorSearchResponse
interface AuthorSearchResponse {
start: number;
numFound: number;
docs: {
type: string;
key: string;
}[];
}
Gränssnittet QueryResult<T>
export interface QueryResult<T> {
totalCount: number;
count: number;
data: T[];
}
Min funktion
// This whole thing produces a QueryResult<Author> instance
return this.httpClient
.get<AuthorSearchResponse>(`${environment.apiUrl}/search/authors.json`, {
params: params,
})
.pipe(
map((searchResponse) =>
searchResponse.docs
.filter(
(doc) => doc.type === 'author' && typeof doc.key !== 'undefined'
)
.map((doc) =>
// getAuthorById returns Observable<Author>
this.authorService.getAuthorById(correctAuthorKey(doc.key))
)
)
)
.pipe(mergeMap((o) => forkJoin(o)))
.pipe(
map((authors) => ({
data: authors,
totalCount: -1,
count: authors.length,
}))
);
Mitt problem är att jag för närvarande inte har något sätt att skicka searchResponse-objektet till den slutliga operatorn, vilket jag verkligen skulle behöva för att sätta totalCount-egenskapen i den slutliga mappningen. Finns det något sätt i RxJs att ta både searchResponse OCH Observable<Author>[]-arrayen som produceras i den första map-operatorn, och när forkJoin är klar (alla Authors har laddats och QueryResult kan produceras), använda searchResponse och de producerade Author[] nedströms för att kombinera dem till ett objekt?
Svar #1
Du kommer att behöva nästla ditt rör genom att pipa forkJoin och använda mergeMap innan map:
return this.httpClient.get<AuthorSearchResponse>(
`${environment.apiUrl}/search/authors.json`,
{ params: params }
).pipe(
mergeMap((searchReponse) => forkJoin(searchReponse.docs
.filter((doc) => doc.type === 'author' && doc.key != null)
.map((doc) => this.authorService.getAuthorById(correctAuthorKey(doc.key)))
).pipe(
map((authors) => ({
data: authors,
totalCount: searchReponse.numFound,
count: authors.length,
}))
))
);
