Слияние наблюдаемого высшего порядка в существующий объект - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть объект, который должен быть заполнен информацией, которую я должен получить по проводам.Новая информация должна храниться в том же объекте

Например:

const apps = {
com.foobar.bar: {
    title:pancake,  
    existingInfo: bar
    },
com.company.android: {
    title: foobar,
    existingInfo: barfoo
    }
}

Для каждого идентификатора внутри приложений я хочу вызвать API отдыха, который даст некоторые дополнительные поля, которые я могу добавитьк объекту.Поток не должен ждать завершения всех остальных вызовов, он должен начинаться с возврата начального значения и затем генерировать обновленный объект для каждого полученного restcall.

В первый раз любой из остальных вызовов возвращает егодолжен заполнять только правильное поле.

{
    com.foobar.bar: {
        title:pancake,  
        existingInfo: bar,
        newStuff: foobar  //let say this is the response we get from the first restcall
        },
    com.company.android: {
        title: foobar,
        existingInfo: barfoo
    }
}

Обновление: мне удалось заставить код работать, но я думаю, что, возможно, это можно сделать по-другому.

const apps$ = of(apps).pipe(
  mergeMap((apps:any) => { //**1**
    const appPromise = Object.keys(apps).map((appId) => {
      return fetchExternalAppInfo(appId).pipe(take(1));
    })
    appP.unshift(of(apps));
    return of(appP).pipe(mergeAll())
  }),
  mergeAll(),
  scan((acc, curr) => { //**2**
    if (!acc) {
      acc = curr;
    } else {
      acc[curr.appId] = Object.assign(acc[curr.appId], curr)
    }
    return acc
  }, null),
  map((result) => { //converting to an array which is ordered by title
    return _.orderBy(result, 'title')
  }),
)     

** 1 = Это вернет массив Observable, который должен быть передан непосредственно в mergeAll ().Это правильный способ подписаться и объединить массив Observable

** 2 = Я знаю, что первый Объект, который передается этой функции, является моим начальным значением (appPromise.unshift (из (приложения))).Вот как я могу сохранить старое начальное значение и добавить к нему новое значение.


* ОБНОВЛЕНИЕ 2 *

Это еще одно решение, и я думаю, что этоГораздо лучше: здесь я использую CombineLates для редактирования исходного объекта.

const fetchedApps$ = applist$.pipe(
  mergeMap((apps:any) => { //*1
    const appPromise = Object.keys(apps).map((appId) => {
      return fetchExternalAppInfo(appId).pipe(take(1));
    })
    return of(appP).pipe(mergeAll())
  }),
  mergeAll(),
  scan((acc, curr:any = {}) => {
    acc[curr.appId] = curr;
    return acc;
  }, {}),
);

const apps$ = combineLatest(of(apps), fetchedApps$).pipe(
  map(([a,b]) => {
    return _.merge(a,b)
  }),
  map((result) => {
    return _.orderBy(result, 'title')
  }),

// * 1 Есть ли другой способ "начать подписку" на массиве наблюдаемыхкроме вызова mergeAll () дважды?

1 Ответ

0 голосов
/ 02 февраля 2019

Я думаю, вы уже очень близки к лучшему решению.Читая ваш код, я думаю, что эти подсказки могут помочь вам улучшить ваш код:

  • from преобразует массив значений в поток значений, так что эти Object.keys могут бытьслиться с внешней наблюдаемой)

  • startWith позволяет нам использовать начальное значение, чтобы вы могли реализовать немедленное первое уведомление

Это может быть реализация:

const fetchedApps$ = applist$.pipe(
    mergeMap((apps:any) => from(Object.keys(apps))),
    mergeMap(key => fetchExternalAppInfo(key).pipe(first())),
    scan((acc, curr:any = {}) => {
        acc[curr.appId] = curr;
        return acc;
    }, apps),
    startWith(apps),
    map(result => _.orderBy(result, 'title'))
);

Скажите, работает ли это для вас или в вашем коде есть что-то, что мешает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...