如何正确使用forkJoin

时间:2018-11-03 07:17:39

标签: javascript firebase rxjs google-cloud-firestore observable

我对内部Observables有疑问。

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 :(得分:1)

如果我正确理解您的问题,则可能是解决方案的一些建议。

至少对于我来说,为了使事情更清楚一点,我将开始创建一个函数,该函数期望输入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数组并创建一个 Observable发出数组的每个元素。
  • 在第二个运算符map中,您开始创建一个Observables数组,该数组表示从category开始提取categoryId的请求,然后返回一个对象,该对象具有word的内容(我假设类型Word的属性word包含实际单词)和关联的类别请求
  • 然后我需要使用forkJoin来执行请求,因此我使用mergeMap将前一个map运算符返回的对象转换为一个Observable,该对象将在所有请求翻译时发出从categoryIdscategories到某个word已完成
  • pipe之后的forkJoin只是用来创建具有wordcategories属性的对象

由于我没有随时可用的Firebase环境,因此我使用以下代码模拟了Firebase Observables

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])
}

答案 1 :(得分:0)

尝试一下:

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
      }))
    ))
  ))
);