需要进行多次 HTTP 调用并合并结果
Need to make multiple HTTP calls and merge results
我有一个问题,由于我对 Angular (v6.0)、RxJs (v6.0) 和 observables 的经验不足,在过去的一周里引起了一些相当大的麻烦。
组件使用的服务需要输出数据模型集合,但这样做需要四个单独的 api 调用,而且我遇到了相关数据的问题,可以选择停止 return 的数据模型。
基本流程
- 第一个 api 调用获取主要实体并创建初始数据
模型集合。
- 第二个api调用将去获取相关数据
并将其添加到数据模型中。
- 第三个 api 调用将去获取
相关数据(如果存在)并将其添加到数据模型中。
- 第四个
api call 会去获取最近相关的相关数据
来自第三次 api 调用的条目。然后是数据模型收集
returned.
设计
- 第二次、第三次、第四次api调用批量查询方法是
使用基于一个ID的集合来减少调用次数,
这没关系,因为我们一次只请求 10、20 条记录。
预期
- 如果没有主要实体 return 从第一个 api 调用所有
不会发生以下调用。
- 第二次 api 调用总会有数据 returned。
- 如果没有从第三次 api 调用中 returned 相关数据,这不是问题,但应该 returned 数据模型集合。
- 如果没有从第三次 api 调用中 returned 相关数据,第四次 api 调用将不会发生,但应该 returned 数据模型集合。
问题
- 确保在没有结果时 return 编辑数据模型集合
发现第三次和第四次 api 调用发生。
- 我无法更改 api。
已知
- 我没有太多的错误处理方式。
- 可能有很多错误,抱歉。
- 这是一个长链,最好分成更小的块。
- 我对 JavaScript 的体验很生疏。
尝试过
- 我已经广泛研究了“*map”函数和 'forkJoin' 但是
无法让任何东西正常工作,并且使用 RxJs
大多数示例适用于低于 6.0 的版本,因此很难
翻译。
代码
我很想缩短它,但我们调用 api 的方式在这里很重要。
return this.agentService.GetByFilter(query)
.pipe(
map(agents => {
let deployments : AgentDeployment[] = [];
for(let i = 0; i < agents.length; ++i) {
deployments.push(new AgentDeployment(agents[i].id, agents[i].name, agents[i].tags));
};
return deployments;
}),
map(deployments => {
// Getting related tags assoiciated with the agent
let tagIds : Array<number> = [];
// Get tag id's
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].tagIds) {
for(let y = 0; y < deployments[i].tagIds.length; ++y) {
if (!tagIds.includes(deployments[i].tagIds[y])) {
tagIds.push(deployments[i].tagIds[y]);
}
};
}
}
// Get the tags associated with the agents
let filter = new Filter();
filter.Field = 'ID';
filter.Value = tagIds.join(',');
// Get tags using list of tag id's
return this.tagService.GetByFilter(filter).pipe(
map(tags => {
if (tags.length) {
for(let i = 0; i < tags.length; ++i) {
// Find the agent
deployments.forEach(deployment => {
if (deployment.tagIds && deployment.tagIds.includes(tags[i].id)) {
deployment.tags.push(tags[i]);
}
});
}
}
return deployments;
}));
}),
mergeMap(deployments => deployments),
map(deployments => {
// Getting deployments related to the agent, an agent may not have any deployment packages associated
let agentIds : Array<number> = [];
// Get tags
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].id) {
agentIds.push(deployments[i].id);
}
}
// Get the deployment packages for the agents
let filter = new Filter();
filter.Field = 'AgentId';
filter.Value = agentIds.join(',');
// Get agent deployment packages using list of agent id's
return this.agentDeploymentPkgService.GetByFilter(filter)
.mergeMap(packages => packages)
.groupBy(pkg => pkg.id)
.map(pkg$ => {
if (pkg$) {
// Add packages to agent deployment
pkg$.map(pkg => {
// Find the agent
let i : number = deployments.findIndex(agent => agent.id == pkg$.key);
if (pkg.deploymentPackageIds) {
// Keep last deployment ID handy
deployments[i].lastDeploymentId = Math.max.apply(null, pkg.deploymentPackageIds);;
deployments[i].deployments.push(new Deployment(pkg.id, pkg.name))
}
});
}
return deployments;
});
}),
mergeMap(deployments => deployments),
map(deployments => {
// Get the logs for the most recent deployment package for the agent, may not exist if no recent deployment package
let deploymentPackageIds : Array<number> = [];
// Get tags
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].id) {
deploymentPackageIds.push(deployments[i].lastDeploymentId);
}
}
// Get the deployment packages for the agents
let filter = new Filter();
filter.Field = 'DeploymentPackageId';
filter.Value = deploymentPackageIds.join(',');
// Get agent deployment log based on the last
this.logService.GetByFilter(filter)
.map(logs => {
logs.forEach(log => {
// Find the agent
let i : number = deployments.findIndex(agent => agent.lastDeploymentId == log.deploymentPackageId);
deployments[i].logId = log.id;
deployments[i].status = log.lastReportedStatusMessage;
});
return deployments;
});
return deployments;
})
);
这里的快速答案是
forkJoin
查看文档
我有一个问题,由于我对 Angular (v6.0)、RxJs (v6.0) 和 observables 的经验不足,在过去的一周里引起了一些相当大的麻烦。
组件使用的服务需要输出数据模型集合,但这样做需要四个单独的 api 调用,而且我遇到了相关数据的问题,可以选择停止 return 的数据模型。
基本流程
- 第一个 api 调用获取主要实体并创建初始数据 模型集合。
- 第二个api调用将去获取相关数据 并将其添加到数据模型中。
- 第三个 api 调用将去获取 相关数据(如果存在)并将其添加到数据模型中。
- 第四个 api call 会去获取最近相关的相关数据 来自第三次 api 调用的条目。然后是数据模型收集 returned.
设计
- 第二次、第三次、第四次api调用批量查询方法是 使用基于一个ID的集合来减少调用次数, 这没关系,因为我们一次只请求 10、20 条记录。
预期
- 如果没有主要实体 return 从第一个 api 调用所有 不会发生以下调用。
- 第二次 api 调用总会有数据 returned。
- 如果没有从第三次 api 调用中 returned 相关数据,这不是问题,但应该 returned 数据模型集合。
- 如果没有从第三次 api 调用中 returned 相关数据,第四次 api 调用将不会发生,但应该 returned 数据模型集合。
问题
- 确保在没有结果时 return 编辑数据模型集合 发现第三次和第四次 api 调用发生。
- 我无法更改 api。
已知
- 我没有太多的错误处理方式。
- 可能有很多错误,抱歉。
- 这是一个长链,最好分成更小的块。
- 我对 JavaScript 的体验很生疏。
尝试过
- 我已经广泛研究了“*map”函数和 'forkJoin' 但是 无法让任何东西正常工作,并且使用 RxJs 大多数示例适用于低于 6.0 的版本,因此很难 翻译。
代码
我很想缩短它,但我们调用 api 的方式在这里很重要。
return this.agentService.GetByFilter(query)
.pipe(
map(agents => {
let deployments : AgentDeployment[] = [];
for(let i = 0; i < agents.length; ++i) {
deployments.push(new AgentDeployment(agents[i].id, agents[i].name, agents[i].tags));
};
return deployments;
}),
map(deployments => {
// Getting related tags assoiciated with the agent
let tagIds : Array<number> = [];
// Get tag id's
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].tagIds) {
for(let y = 0; y < deployments[i].tagIds.length; ++y) {
if (!tagIds.includes(deployments[i].tagIds[y])) {
tagIds.push(deployments[i].tagIds[y]);
}
};
}
}
// Get the tags associated with the agents
let filter = new Filter();
filter.Field = 'ID';
filter.Value = tagIds.join(',');
// Get tags using list of tag id's
return this.tagService.GetByFilter(filter).pipe(
map(tags => {
if (tags.length) {
for(let i = 0; i < tags.length; ++i) {
// Find the agent
deployments.forEach(deployment => {
if (deployment.tagIds && deployment.tagIds.includes(tags[i].id)) {
deployment.tags.push(tags[i]);
}
});
}
}
return deployments;
}));
}),
mergeMap(deployments => deployments),
map(deployments => {
// Getting deployments related to the agent, an agent may not have any deployment packages associated
let agentIds : Array<number> = [];
// Get tags
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].id) {
agentIds.push(deployments[i].id);
}
}
// Get the deployment packages for the agents
let filter = new Filter();
filter.Field = 'AgentId';
filter.Value = agentIds.join(',');
// Get agent deployment packages using list of agent id's
return this.agentDeploymentPkgService.GetByFilter(filter)
.mergeMap(packages => packages)
.groupBy(pkg => pkg.id)
.map(pkg$ => {
if (pkg$) {
// Add packages to agent deployment
pkg$.map(pkg => {
// Find the agent
let i : number = deployments.findIndex(agent => agent.id == pkg$.key);
if (pkg.deploymentPackageIds) {
// Keep last deployment ID handy
deployments[i].lastDeploymentId = Math.max.apply(null, pkg.deploymentPackageIds);;
deployments[i].deployments.push(new Deployment(pkg.id, pkg.name))
}
});
}
return deployments;
});
}),
mergeMap(deployments => deployments),
map(deployments => {
// Get the logs for the most recent deployment package for the agent, may not exist if no recent deployment package
let deploymentPackageIds : Array<number> = [];
// Get tags
for(let i = 0; i < deployments.length; ++i) {
if (deployments[i].id) {
deploymentPackageIds.push(deployments[i].lastDeploymentId);
}
}
// Get the deployment packages for the agents
let filter = new Filter();
filter.Field = 'DeploymentPackageId';
filter.Value = deploymentPackageIds.join(',');
// Get agent deployment log based on the last
this.logService.GetByFilter(filter)
.map(logs => {
logs.forEach(log => {
// Find the agent
let i : number = deployments.findIndex(agent => agent.lastDeploymentId == log.deploymentPackageId);
deployments[i].logId = log.id;
deployments[i].status = log.lastReportedStatusMessage;
});
return deployments;
});
return deployments;
})
);
这里的快速答案是
forkJoin
查看文档