使用 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(...