Как правильно использовать forkJoin - PullRequest
0 голосов
/ 03 ноября 2018

У меня проблема с внутренними наблюдаемыми.

const wordsCollection = this.db.collection('words').valueChanges();

return wordsCollection.pipe(
      map((words: Word[]) => {
        return words.map((word: Word) => {
          const categories = word.categories.map((categoryId: string) => {
            return this.db.collection('categories').doc(categoryId).valueChanges().pipe(
              map((category: Category) => {
                return category;
              })
            );
          });
          return {
            ...word,
            categories: categories
          };
        });
      })
    );

и результат будет примерно таким:

{
word: 'blabla',
categories: Observable (instead of for example 'english')
}

Я знаю, что мне нужно использовать что-то вроде forJoin, но не знаю, как это правильно использовать. Любая помощь?

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

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

Чтобы сделать вещи немного более понятными, по крайней мере для меня, я бы начал создавать функцию, которая ожидает categoryId в качестве ввода и возвращает Observable категории, то есть что-то вроде

function getCategory(categoryId: number) {
  return this.db.collection('categories').doc(categoryId).valueChanges();
}

Тогда я бы построил Observable, который мне нужен, вот так

wordsCollection.pipe(
  mergeMap(words => words),
  map(word => {
    const categoryRequests = word.categories.map(categoryId => getCategory(categoryId));
    return {word: word.word, categoryRequests};
  }),
  mergeMap(({word, categoryRequests}) => forkJoin(categoryRequests).pipe(map(categories => ({word, categories}))))
)

Здесь ключевыми моментами являются следующие

  • Первый mergeMap выравнивает массив words и создает Наблюдаемый, который испускает каждый элемент массива.
  • Во втором операторе, map, вы начинаете создавать массив наблюдаемых, который представляет запросы на выборку category, начиная с его categoryId, а затем вы возвращаете объект, имеющий оба содержимого word (я предполагаю, что тип Word имеет свойство word, которое содержит фактическое слово) и запросы категории, связанные
  • тогда мне нужно использовать forkJoin для выполнения запросов, и поэтому я использую mergeMap для преобразования объекта, возвращенного предыдущим оператором map, в Observable, который выдает, когда все запросы переводят categoryIds в categories на определенное время word завершили
  • pipe после forkJoin просто для создания объекта с word и categories свойствами

Поскольку у меня нет готовой среды Firebase, я смоделировал наблюдаемые Firebase с помощью следующего кода

const words = [
  {word: 'abc', categories: [1, 2, 3]},
  {word: 'cde', categories: [3, 4, 5]},
];

const categories = {
  1: 'X',
  2: 'Y',
  3: 'Z',
  4: 'X',
  5: 'W',
}

function getCategory(categoryId: number) {
  return of(categories[categoryId])
}
0 голосов
/ 03 ноября 2018

Попробуйте:

const wordsCollection = this.db.collection('words').valueChanges();

return wordsCollection.pipe(
  mergeMap((words: Word[]) => Rx.of(...words).pipe(
    mergeMap((word: Word) => Rx.of(...word.categories).pipe(
      mergeMap(categoryId => this.db.collection('categories').doc(categoryId).valueChanges()),
      toArray(),
      map(categories => ({
        ...word,
        categories
      }))
    ))
  ))
);
...