Rxjs сопоставить массив в документе Json с новым типом массива

Я получаю документ из PouchDB в службе Angular. Документ извлекается в следующем формате:

{
"_id":"segments",
"_rev":"1-4f0ed65cde23fe724db13bea1ae3bb13",
"segments":[
    { "name":"Aerospace" },
    { "name":"Auto repair" },
    { "name":"Commercial" },
    { "name":"Education" },
    { "name":"Energy" },
    { "name":"Farm/ranch" },
    { "name":"Furniture" },
    { "name":"Heavy Equipment" },
    { "name":"Hobbyist" },
    { "name":"Infrastructure" },
    { "name":"Luxury/Leisure" },
    { "name":"Military" },
    { "name":"MUP" },
    { "name":"Processing" },
    { "name":"Rail" },
    { "name":"Transportation" }
]}

И я хочу сопоставить это с новым массивом, который будет выглядеть так:

[
  { value: "Aerospace", viewValue: "Aerospace" },
  { value: "Auto Repair", viewValue: "Auto Repair" },
  { value: "Commercial", viewValue: "Commercial" }
  ...
 ]

Для этого я попробовал этот код в своей службе:

getSegments(): Observable<any[]> {
  return from(this.database.get('segments'))
  .pipe(
    map((results) => results.segments)
  );
}

И я преобразовываю массив в моем компоненте следующим образом:

segments: SegmentsLookup[] = [];
...
this.lookupDbService.getSegments()
  .subscribe(data => {
    data.forEach(element => {
      this.segments.push({value: element.name, viewValue: element.name});
  });
});

Это работает, но я знаю, что есть способ правильно отобразить это в служебном коде. Кроме того, когда это делается таким образом, компилятор жалуется на «результаты. сегменты», указывая, что «сегменты свойства» не существуют для типа '{}'.

Как сопоставить полученные данные с нужным мне массивом в методе "getSegments" службы?


person Eric    schedule 30.08.2018    source источник


Ответы (3)


Сделать преобразование можно в 2 шага:

  • труба / карта для извлечения сегментов
  • массив / карта для преобразования в окончательный тип данных

См. Пример здесь: https://stackblitz.com/edit/angular-ikb2eg?file=src%2Fapp%2Fapp.component.ts

let transformedData = observableData.pipe(
  map(data => {
    console.log(data, data.segments.length);
    return data.segments.map(element => {
      return { value: element["name"], viewValue: element["name"] };
    });
  })
);

transformedData.subscribe(data => {
  this.mylist = data;
});
person hamilton.lima    schedule 30.08.2018

Вы можете использовать оператор RxJS flatMap, который является псевдонимом mergeMap.

Официальная документация описывает flatMap следующим образом:

Проецирует каждый элемент наблюдаемой последовательности в наблюдаемую последовательность и объединяет полученные наблюдаемые последовательности или обещания или массив / итерацию в одну наблюдаемую последовательность.

Мы можем использовать flatMap, а затем оператор RxJS map следующим образом:

  • flatMap для извлечения сегментов
  • map для преобразования в окончательный тип данных
const transformedData = observableData.pipe(
  flatMap(data => data.segments),
  map(segment => ({
    value: segment['name'],
    viewValue: segment['name'],
  })),
)

transformedData.subscribe(data => {
  this.mylist = data;
});

Подробное объяснение того, как это работает:

Эта статья хорошо объясняет, как работает flatMap, и реализует версию flatMap, которая работает с массивами, а не с наблюдаемыми объектами RxJS, а именно:

function flatMap (arr, fn) {
  return arr.reduce((flatArr, subArray) => flatArr.concat(fn(subArray)), [])
}

Если мы используем это с результатом вашего запроса к базе данных, мы увидим, что извлекаем сегменты.

const data = {
"_id": "segments",
"_rev": "1-4f0ed65cde23fe724db13bea1ae3bb13",
"segments": [
  { "name": "Aerospace" },
  { "name": "Auto repair" },
  // ...
]};

const segments = flatMap([data], x => x.segments);

console.log(segments);

// > [
// >  { "name": "Aerospace" },
// >  { "name": "Auto repair" },
// >  ...
// > ]

Оператор RxJS flatMap возвращает наблюдаемый поток сегментов, а не массив сегментов.

person matthew    schedule 20.04.2020
comment
Вам понадобится combineAll(), чтобы преобразовать его обратно в массив? - person df1; 13.07.2020

Вы можете расширить функцию карты и удалить ее из компонента следующим образом:

map(result => {
        result = result.segments;
        let data = [];
        result.forEach(element => {
            data.push({value: element.name, viewValue: element.name});
        });
        return data;
 });
person Avinash Lahel    schedule 30.08.2018