从 Firestore 中检索文档引用的值

Posted

技术标签:

【中文标题】从 Firestore 中检索文档引用的值【英文标题】:Retrieving value of document references from firestore 【发布时间】:2021-05-06 08:24:45 【问题描述】:

我正在尝试从 firestore(一个问题对象)中检索一个对象,该对象除其他外具有一些 DocumentReference 类型的字段(例如:主题,指的是主题集合中的一个文档)。这里的目标是从问题集合中检索所有问题对象,在表格中显示它们的所有属性,并且应该解析 DocumentReferences,并且应该显示检索到的对象的“名称”属性。解决所有问题很容易,但出于某种原因,我为解决 DocumentReferences 所做的工作导致整个应用程序冻结

themes.service.ts

  getThemeNameByRef(ref: DocumentReference): Observable<string> 
     if (ref) 
         return this.db.doc(`themes/$ref.id`).get()
         .pipe(
           map((action) => 
              return action.data().name;
           ), shareReplay(1))

      

问题-explorer.component.html

  <div *ngFor="let question of questions">
    question.difficulty
    themeService.getThemeNameByRef(question.theme) | async
  </div>

我已将其包含在表格中,并使用更简单的方法来消除导致问题的原因。我已经尝试了很多不同的方法来检索引用,比如直接在 DocumentReference 对象上调用 get(),创建一个 AngularFirestoreDocument 对象,我似乎遇到了同样的冻结问题,或者页面会加载但模板会解析值为 null,因此不会显示任何内容。

查看 Chrome 开发工具,只有一个 HTTP 请求发出,但 observable 被无限次调用,这就是导致它冻结的副作用。为什么会这样,但我无法弄清楚。

谢谢!

【问题讨论】:

【参考方案1】:

部分解决方案:

我不确定你发生了什么,我希望问题数组中的每个问题都有一个 HTTP 调用。

无论如何,从长远来看,直接在 HTML 模板中编写数据可能是一个糟糕的选择。如果您的服务调用的结果无序或以不同的时间间隔返回,则很难扩展,并且可能会导致视图显示异常。

在您的组件中,我会写如下内容: (请注意,我不确定questions 是如何定义的,所以我无法建议应该在哪里/如何声明/定义viewQuestions$,这取决于您)

viewQuestions$ = forkJoin(
  this.questions.map(question => 
    themeService.getThemeNameByRef(question.theme).pipe(
      map(theme => (...question, theme))
    )
  )
);

然后在你的 HTML 模板中

<div *ngFor="let question of viewQuestions$ | async">
  question.difficulty
  question.theme
</div>

这有一个更简单的模板的好处。所有的服务调用都在显示之前完成,所以用户屏幕上没有奇怪的闪烁。

您也可以更轻松地调试它。您可以使用 RxJS 运算符来记录结果、捕获错误、重试服务调用等。


例如,如果您想在问题显示之前记录问题,您可以执行以下操作:

viewQuestions$ = forkJoin(
  this.questions.map(question => 
    themeService.getThemeNameByRef(question.theme).pipe(
      map(theme => (...quesiton, theme))
    )
  )
).pipe(
  tap(console.log)
);

进一步抽象构建viewQuestions$

这与上述相同,但适用于任意数量的属性。 forkjoin 的好处是它接受一个字典(JS 对象),并将返回一个形状相同的对象,其属性解析为给定 observables 的最终值。很方便!

你可以看到这里使用的:

viewQuestions$ = this.getQuestionsService(args).pipe(
  switchMap(questions => forkJoin(
    questions.map(question => 
      forkJoin(
        theme: this.themeService.getThemeNameByRef(question.theme),
        property2: this.service.getThingy2(question.something2),
        property3: this.service.getThingy3(question.something3)
      ).pipe(
        map(properties => (...question, ...properties))
      )
    )
  ))
);

在您的模板中:

<div *ngFor="let question of viewQuestions$ | async">
  question.difficulty
  question.theme
  question.property2
  question.property3
</div>

【讨论】:

这真的很漂亮,我理想的解决方案是一次性解决所有问题,这就是您在这里所做的。这将作为构建我的表格的一个很好的起点,因为它可以正确解析文档。感谢您的帮助,请继续做您的事情! 一个问题有多少个 DocumentReference? 目前是 5,我看到你在那里做的很干净。我今晚会实施。谢谢!!

以上是关于从 Firestore 中检索文档引用的值的主要内容,如果未能解决你的问题,请参考以下文章

从 documentSnapshot 获取 Cloud Firestore 文档参考

如何从Swift中的Cloud FireStore Firebase访问特定字段

使用 Swift (Firestore) 访问特定文档字段

从 id 数组中获取 firestore 文档列表

即使我禁用了持久性,Firestore 仍在从缓存中检索文档

Flutter web:从 Firestore 地图检索的值在添加到列表时被截断