繁体   English   中英

从文档引用数组中获取 firestore 文档

[英]Get firestore documents from array of document references

目前,我正在对 Firestore 进行一组非常复杂的查询。

我正在尝试一次填充一个充满对其他文档的引用的数组,然后读取这些文档并将信息放入一个数组中。

更具体地说,对于这个示例,我在一个集合中有 4 个引用。 我想获取这些引用,然后使用这些引用,查询 4 个文档并用信息填充一个数组。

顺序如下:对tags子集合中的所有文档进行查询,由下面的 function 处理:

getTagsOnPage(workspaceId: string, pageId: string) {
    // get all of the references in the tags sub-collection, and puts them in an array
    // get all id's, do not get data
    return this.afs
      .collection("users")
      .doc(`${auth().currentUser.uid}`)
      .collection<Workspace>("workspaces")
      .doc(`${workspaceId}`)
      .collection<Page>("pages")
      .doc(`${pageId}`)
      .collection("tags")
      .snapshotChanges()
      .pipe(
        map((actions) => {
          return actions.map((a) => {
            const ref = a.payload.doc.get("reference");
            return ref; // return an array of (id: reference) key-value pairs
          });
        })
      );
  }

这适用于执行订阅的以下代码:

this.pageService
      .getTagsOnPage(this.workspaceId, this.currentPage.id)
      .subscribe((data) => {
        temp = data;
      });

data如下,通过控制台:

(3) ["/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1…1tSnPI5GJrniY82vZL/localTags/1p5Tscwn14PyK6zRaFHX", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/lFKoB0jngmtnALut2QS2", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/r6sf2SX6v87arU2rKsD5"]

现在,执行下一组数据读取是我开始困惑的地方。

我最初的方法是尝试一个 for 循环(对于这个数组的长度),但这将涉及迭代执行许多嵌套订阅,我认为这在这个意义上是不可能的。

我对 rxjs 相当陌生,并且只使用了 map 和 switchMap 运算符。 在这种情况下,我想我会使用诸如mergeMap和/或flatMap,但坦率地说,我不确定如何在这种情况下进行这项工作。 此外,处理我需要根据我得到的 documentReferences 数组获取文档的 for 循环也让我陷入了循环。

这是我目前的实现,到处都是; 我希望我正在尝试做的事情的感觉就在那里。 基本上,通过 getTagsOnPage 获取引用数组,等待 observable 结束,使用 switchMap 获取数据数组并循环遍历它; 理想情况下,订阅每个 ref 并添加到 tagData,然后返回:

let tagData;
    this.pageService.getTagsOnPage(this.workspaceId, this.currentPage.id).pipe(
      switchMap((data) => {
        let references = data;
        for (let j = 0; j < references.length; j++) {
          let ref = this.afs.doc(`${references[j]}`);
          ref.snapshotChanges().pipe(
            map((actions) => {
              const data = actions.payload.data();
              tagData.push(data);
            })
          );
          // push the data (different data var)
        }
      })
    );
    return tagData;

混乱,我知道,但我认为一旦我知道正确的运营商来使用它就会更有意义。

此外, atm this 返回一个空数组。 当我使用 switchMap 时出现以下错误:

Argument of type '(data: any[]) => void' is not assignable to parameter of type '(value: any[], index: number) => ObservableInput<any>'.
  Type 'void' is not assignable to type 'ObservableInput<any>'.

感谢您的任何帮助!

使用switchMap出错的原因是您没有返回 Observable。

当使用任何“ 高阶映射运算符”(switchMap、concatMap、mergeMap 等)时,提供的 function 必须返回一个 observable。 正如错误所述:“类型void不可分配给类型ObservableInput<any> ”,您没有返回任何内容(void)。

下一件不太正确的事情是,在您的循环中,您引用ref.snapshotChanges().pipe() ,但您从未订阅它。 如您所知,可观察对象是惰性的,除非有订阅者,否则不会触发。

只要你在switchMap()中返回一个 observable,它就会自动订阅它并发出它的值。

让我们换个角度想一想; 而不是循环第一次调用的结果,执行它们,然后将值推送到数组中。 我们可以取而代之,将结果转换为可观察的 stream,它会发出它们各自调用的所有结果,并将它们组合成一个数组供您使用。 但是......有一个细微的区别:我建议不要在 stream 之外有一个单独的tagData数组,而是让你的 observable 返回你需要的tagData表单作为Observable<TagData[]>

我认为这样的事情对你有用:

tagData$ = this.pageService.getTagsOnPage(this.workspaceId, this.currentPage.id).pipe(
    switchMap(references => from(references)),
    mergeMap(ref => this.afs.doc(ref).snapshotChanges()),      
    map(actions => actions.payload.data()),
    scan((allTagData, tagData) => [...allTagData, tagData], [])
  })
);

让我们打破它!

  1. 我们使用from从您的数组中创建一个 observable,它一次发出每个“引用”。

  2. mergeMap将订阅我们正在创建的 observable 并发出它的发射

  3. map只是将值转换为您想要的形状

  4. scan会为您累积排放量,并在每次更改时排放量。 如果您不想在所有调用返回之前发出,请改用reduce()

现在,您可以简单地执行以下操作: tagData$.subscribe()并对生成的数据数组执行您想要的操作。 或者你甚至可以在你的模板中使用异步 pipe而不是在你的组件中订阅。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM