如何在 Angular 中使用多个 API 调用从数据库中查询嵌套数据?
How to query nested data from database using multiple API calls in Angular?
我正在学习angular和API服务。目前,我使用 router
重定向到使用 group id
的组详细信息页面
这是我想要实现的目标:
在详情页面,我想在angular页面显示用户名和用户城市,需要多个API 调用(可能需要按顺序)从 group data
.
获取数据
- 我需要使用
route id/group id
通过 getGroup()
获取组对象
- 每个组包含多个用户Id
- (获取用户名)我需要迭代每个 用户 ID 以获得
user object
其中包含 用户名 和城市 ID 来自 getUser()
- (获取城市名称)我需要迭代每个 city IDs 以获得
city object
其中包含 city ids 和城市名称 来自 getCity()
所有数据概览:
######### group data
{
"groups": [
{
"id": "group_id1",
"users": ["user_id1", "user_id2"]
},
{
"id": "group_id2",
"users": ["user_id3", "user_id4"]
}
]
}
######### user data
{
"users": [
{
"id": "user_id1",
"city": ["city_id1", "city_id2"]
},
{
"id": "user_id2",
"city": ["city_id3", "city_id4"]
},
{
"id": "user_id3",
"city": ["city_id1", "city_id3"]
},
{
"id": "user_id4",
"city": ["city_id2", "city_id4"]
}
]
}
######### city data
{
"cities": [
{
"id": "city_id1",
"name": "NY"
}
{
"id": "city_id2",
"name": "BOS"
}
{
"id": "city_id3",
"name": "SF"
}
{
"id": "city_id4",
"name": "LA"
}
]
}
目前,我可以获取组,但我不知道如何获取用户名和城市。
## component.ts
export class displayComponent implements OnInit {
group$!: Observable<group>;
constructor(
private router: Router,
private route: ActivatedRoute,
private groupService: GroupService,
private userService: UserService,
private cityService: CityService,
) {}
ngOnInit(): void {
this.group$ = this.route.params.pipe(
switchMap((params) => this.groupService.getGroup(params.id))
);
// how to iterate all **user Id** to get user names via `getUser(**user Id**)`
// how to iterate all **city Id** to get city names via `getCity(**city Id**)`
}
## html
<div *ngIf="group$ | async as group">
<p> {{ group.id }} </p>
<!-- user names placeholder-->
<!-- user city names placeholder-->
</div>
链接请求就可以了,它会像这样:
Your_Source.pipe(
switchMap((params) => this.groupService.getGroup(params.id))
switchMap((params) => this.userService.getUser(params.id))
switchMap((params) => this.cityService.getCity(params.id))
);
希望对您有所帮助。
是关于RxJs的。应该是这样的。虽然未测试
private getCitiesInfo() {
this.http.get('getGroupByIdApi')
.pipe(
map(group => groups.users),
switchMap(userIds => this.constructGetUsersRequest(userIds)),
map(usersData => usersData.flat().map(user => user.city)),
switchMap(cityIds => this.constructGetCityRequests(cityIds))
).subscribe();
}
private constructGetUsersRequest(userIds: string[]): Observable<User>[] {
const requests: Observable<User>[] = userIds.map(userId => this.http.get('userIdGetApi'));
return combineLatest(requests);
}
private constructGetCityRequests(cityIds: string[]): Observable<City>[] {
const requests: Observable<City>[] = cityIds.map(cityId => this.http.get('cityIdGetApi'));
return combineLatest(requests);
}
我不建议您分别为每个用户和城市提出请求。该操作将永远持续下去,因为您将为一个页面呈现发出许多 http 请求。您可以从数据库中获取所有城市和所有用户,然后在本地进行过滤。或者您可以在单个请求中生成 API return 所有需要的数据。但是,如果这些选项都不适合您,您可以链接 switchMap 管道操作。例如:
switchMap(group => {
let observable = of({});
group.users.forEach(userId => {
observable = observable.pipe(
switchMap(() => {
return this.userService.getUser(userId);
}),
tap(user => {
...
})
);
});
return observable;
})
编辑:这段代码展示了如何通过首先获取所有城市和用户来实现。
## component.ts
export class displayComponent implements OnInit {
userMap: { [userId: string]: User };
cityMap: { [cityId: string]: City };
group: Group;
constructor(
private router: Router,
private route: ActivatedRoute,
private groupService: GroupService,
private userService: UserService,
private cityService: CityService,
) {}
ngOnInit(): void {
this.userMap = {};
this.cityMap = {};
this.userService.getAllUsers().pipe(
switchMap(users => {
users.forEach(user => {
this.userMap[user.id] = user;
})
return this.cityService.getAllCities();
}),
switchMap(cities => {
cities.forEach(city => {
this.cityMap[city.id] = city;
});
return this.route.params;
}),
switchMap(params => {
return this.groupService.getGroup(params.id);
})
).subscribe(group => {
this.group = group;
});
}
## html
<div *ngIf="group">
<p> {{ group.id }} </p>
<ul>
<li *ngFor="let userId of group.users">
{{ userMap[userId].name }}<br>
<div class="city" *ngFor="let cityId of userMap[userId].city">
{{ cityMap[cityId].name }}
</div>
</li>
</ul>
</div>
我正在学习angular和API服务。目前,我使用 router
重定向到使用 group id
这是我想要实现的目标:
在详情页面,我想在angular页面显示用户名和用户城市,需要多个API 调用(可能需要按顺序)从 group data
.
- 我需要使用
route id/group id
通过getGroup()
获取组对象
- 每个组包含多个用户Id
- (获取用户名)我需要迭代每个 用户 ID 以获得
user object
其中包含 用户名 和城市 ID 来自getUser()
- (获取城市名称)我需要迭代每个 city IDs 以获得
city object
其中包含 city ids 和城市名称 来自getCity()
所有数据概览:
######### group data
{
"groups": [
{
"id": "group_id1",
"users": ["user_id1", "user_id2"]
},
{
"id": "group_id2",
"users": ["user_id3", "user_id4"]
}
]
}
######### user data
{
"users": [
{
"id": "user_id1",
"city": ["city_id1", "city_id2"]
},
{
"id": "user_id2",
"city": ["city_id3", "city_id4"]
},
{
"id": "user_id3",
"city": ["city_id1", "city_id3"]
},
{
"id": "user_id4",
"city": ["city_id2", "city_id4"]
}
]
}
######### city data
{
"cities": [
{
"id": "city_id1",
"name": "NY"
}
{
"id": "city_id2",
"name": "BOS"
}
{
"id": "city_id3",
"name": "SF"
}
{
"id": "city_id4",
"name": "LA"
}
]
}
目前,我可以获取组,但我不知道如何获取用户名和城市。
## component.ts
export class displayComponent implements OnInit {
group$!: Observable<group>;
constructor(
private router: Router,
private route: ActivatedRoute,
private groupService: GroupService,
private userService: UserService,
private cityService: CityService,
) {}
ngOnInit(): void {
this.group$ = this.route.params.pipe(
switchMap((params) => this.groupService.getGroup(params.id))
);
// how to iterate all **user Id** to get user names via `getUser(**user Id**)`
// how to iterate all **city Id** to get city names via `getCity(**city Id**)`
}
## html
<div *ngIf="group$ | async as group">
<p> {{ group.id }} </p>
<!-- user names placeholder-->
<!-- user city names placeholder-->
</div>
链接请求就可以了,它会像这样:
Your_Source.pipe(
switchMap((params) => this.groupService.getGroup(params.id))
switchMap((params) => this.userService.getUser(params.id))
switchMap((params) => this.cityService.getCity(params.id))
);
希望对您有所帮助。
是关于RxJs的。应该是这样的。虽然未测试
private getCitiesInfo() {
this.http.get('getGroupByIdApi')
.pipe(
map(group => groups.users),
switchMap(userIds => this.constructGetUsersRequest(userIds)),
map(usersData => usersData.flat().map(user => user.city)),
switchMap(cityIds => this.constructGetCityRequests(cityIds))
).subscribe();
}
private constructGetUsersRequest(userIds: string[]): Observable<User>[] {
const requests: Observable<User>[] = userIds.map(userId => this.http.get('userIdGetApi'));
return combineLatest(requests);
}
private constructGetCityRequests(cityIds: string[]): Observable<City>[] {
const requests: Observable<City>[] = cityIds.map(cityId => this.http.get('cityIdGetApi'));
return combineLatest(requests);
}
我不建议您分别为每个用户和城市提出请求。该操作将永远持续下去,因为您将为一个页面呈现发出许多 http 请求。您可以从数据库中获取所有城市和所有用户,然后在本地进行过滤。或者您可以在单个请求中生成 API return 所有需要的数据。但是,如果这些选项都不适合您,您可以链接 switchMap 管道操作。例如:
switchMap(group => {
let observable = of({});
group.users.forEach(userId => {
observable = observable.pipe(
switchMap(() => {
return this.userService.getUser(userId);
}),
tap(user => {
...
})
);
});
return observable;
})
编辑:这段代码展示了如何通过首先获取所有城市和用户来实现。
## component.ts
export class displayComponent implements OnInit {
userMap: { [userId: string]: User };
cityMap: { [cityId: string]: City };
group: Group;
constructor(
private router: Router,
private route: ActivatedRoute,
private groupService: GroupService,
private userService: UserService,
private cityService: CityService,
) {}
ngOnInit(): void {
this.userMap = {};
this.cityMap = {};
this.userService.getAllUsers().pipe(
switchMap(users => {
users.forEach(user => {
this.userMap[user.id] = user;
})
return this.cityService.getAllCities();
}),
switchMap(cities => {
cities.forEach(city => {
this.cityMap[city.id] = city;
});
return this.route.params;
}),
switchMap(params => {
return this.groupService.getGroup(params.id);
})
).subscribe(group => {
this.group = group;
});
}
## html
<div *ngIf="group">
<p> {{ group.id }} </p>
<ul>
<li *ngFor="let userId of group.users">
{{ userMap[userId].name }}<br>
<div class="city" *ngFor="let cityId of userMap[userId].city">
{{ cityMap[cityId].name }}
</div>
</li>
</ul>
</div>