使用 Observable 而不是 Promise 来映射对象数组
Use Observable instead of Promise to map an array of objects
问题:
当我从服务器获取数据时,我得到了一些格式为的对象:
{
list: {
pagination: {},
entries: []
}
}
我需要检查条目并更改它们。要更改它们,我需要为每个条目调用一些 REST API(例如:在第一次调用中我将获得 ID,对于每个 ID,我需要获得真实数据)。在完成每个对象的所有 REST 调用后,我需要更改其数据。所以 entries[i] = 从 id 到真实数据。
我用 Promises 解决了这个问题,但我想用 Observables 来解决这个问题。
我尝试使用 rxjs 中的 map 和 concatMap 但没有成功。
代码:
public getUsers(queryBody?: SearchRequest): Observable<PersonPaging> {
const searchRequest =
queryBody ||
this.searchService.makeSearchRequest(
new Query({ type: ContentModel.TYPE_PERSON })
);
return this.searchService
.search(searchRequest)
.pipe(
switchMap(async (resultSetPaging: ResultSetPaging) => {
const users: PersonPaging = {
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
};
for (const rowEntry of resultSetPaging.list.entries) {
const { properties } = rowEntry.entry;
const personEntry = await this.getUser(
properties[ContentModel.PROP_USERNAME]
).toPromise();
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
users.list.entries.push(personEntry);
}
return users;
})
);
}
问题结束
正在处理代码:
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) => {
return from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
).pipe(
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
})
);
})
);
})
);
使用此代码,我让所有用户都修改了数据,但我没有通过分页获得我想要的对象。它调用了 x 次(x - users/entries 的数量)
我不是 100% 确定您希望它的格式如何,但这应该让您接近。听起来您真正需要做的就是将 Person
列表缩减为 users.list.entries
上的数组?那看起来像这样:
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) => {
return from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
).pipe(
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
})
);
}),
reduce(
(users, personEntry) => {
users.list.entries.push(personEntry);
return users;
},
{
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
}
)
);
})
);
或者可能更干净一点(虽然是一样的)
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
);
}),
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
}),
reduce(
(users, personEntry) => {
users.list.entries.push(personEntry);
return users;
},
{
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
}
)
)
)
);
旁白:我还想知道您的第一张地图是否按预期工作。看起来您正在返回一个流,所以您可能需要 mergeMap?
map((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(...
到
mergeMap((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(...
问题: 当我从服务器获取数据时,我得到了一些格式为的对象:
{
list: {
pagination: {},
entries: []
}
}
我需要检查条目并更改它们。要更改它们,我需要为每个条目调用一些 REST API(例如:在第一次调用中我将获得 ID,对于每个 ID,我需要获得真实数据)。在完成每个对象的所有 REST 调用后,我需要更改其数据。所以 entries[i] = 从 id 到真实数据。
我用 Promises 解决了这个问题,但我想用 Observables 来解决这个问题。
我尝试使用 rxjs 中的 map 和 concatMap 但没有成功。
代码:
public getUsers(queryBody?: SearchRequest): Observable<PersonPaging> {
const searchRequest =
queryBody ||
this.searchService.makeSearchRequest(
new Query({ type: ContentModel.TYPE_PERSON })
);
return this.searchService
.search(searchRequest)
.pipe(
switchMap(async (resultSetPaging: ResultSetPaging) => {
const users: PersonPaging = {
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
};
for (const rowEntry of resultSetPaging.list.entries) {
const { properties } = rowEntry.entry;
const personEntry = await this.getUser(
properties[ContentModel.PROP_USERNAME]
).toPromise();
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
users.list.entries.push(personEntry);
}
return users;
})
);
}
问题结束
正在处理代码:
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) => {
return from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
).pipe(
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
})
);
})
);
})
);
使用此代码,我让所有用户都修改了数据,但我没有通过分页获得我想要的对象。它调用了 x 次(x - users/entries 的数量)
我不是 100% 确定您希望它的格式如何,但这应该让您接近。听起来您真正需要做的就是将 Person
列表缩减为 users.list.entries
上的数组?那看起来像这样:
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) => {
return from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
).pipe(
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
})
);
}),
reduce(
(users, personEntry) => {
users.list.entries.push(personEntry);
return users;
},
{
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
}
)
);
})
);
或者可能更干净一点(虽然是一样的)
return this.searchService.search(searchRequest).pipe(
map((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(
concatMap(rowEntry => {
const { properties } = rowEntry.entry;
return from(
this.getUser(properties[ContentModel.PROP_USERNAME])
);
}),
map(personEntry => {
const person: Person = personEntry.entry;
person.avatarId = this.getUserAvatarImage(person);
return { person };
}),
reduce(
(users, personEntry) => {
users.list.entries.push(personEntry);
return users;
},
{
list: {
pagination: resultSetPaging.list.pagination,
entries: []
}
}
)
)
)
);
旁白:我还想知道您的第一张地图是否按预期工作。看起来您正在返回一个流,所以您可能需要 mergeMap?
map((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(...
到
mergeMap((resultSetPaging: ResultSetPaging) =>
from(resultSetPaging.list.entries).pipe(...