I'm using rxjs
to make several http requests and I want to end up with an object that looks something like:
{
100: {
...response from api call...
},
205: {
...response from api call...
},
...etc...
}
Here's what I have so far:
const projectIds = [100, 205, 208, 300]
const source = Rx.Observable
.from(projectIds)
.flatMap(id => get(`projects/${id}/builds`))
.map(response => response['data'])
.zip(projectIds)
.toArray()
source.subscribe(pipelines => {
console.log(pipelines)
})
This gives me back an array of arrays where the first element is the response from the call and the second element is the id of the project.
The problem is that the response doesn't match the project id as the responses come back in different orders depending on which request completes first.
How can I preserve the order (or at least know which projectId goes with each response) while also ending up with an object at the end (currently is an array)?
Just use the flatMap
with elementSelector
overload:
.flatMap(
projectId => getProjectDetails(projectId),
(projectId, details) => ({ id: projectId, details })
)
function getProjectDetails(id){
return get(`projects/${id}/builds`)
.map(response => response['data']);
}
This will let you combine the input argument and every output value from flatMap as you require, effectively preserving context. If you require the output order to stay the same you can use .concatMap
but then all emissions are done after each other instead of concurrently.
Then finally use a .reduce
to combine all objects back to one big emission:
.reduce((acc, curr) => acc[curr.id] = curr.details, {})
Option 1
Instread of flatMap
you could use concatMap
, that should preserve the order.
Note: This won't make any concurrent requests though, if that is what you are looking for.
Option 2
If you want to make concurrent requests (at least from the RxJS side, depending on the browser this could still be limited) you could use some construct using forkJoin
like the following:
const projectIds = [100, 205, 208, 300]
const source = Rx.Observable
.from(projectIds)
.map(id => get(`projects/${id}/builds`).pluck('data'))
.toArray()
.switchMap(requestArray => Rx.Observable.forkJoin(requestArray))
.zip(projectIds)
source.subscribe(pipelines => {
console.log(pipelines)
})