服务器时间戳上的集合订阅 returns 为空

Collection subscription returns null on server timestamp

我正在向名为 workReports 的子集合添加文档,同时我订阅了它。

查询方法:

getWorkReportsByProjectId(projectId: string): Observable<ProjectWorkReport[]> {

  return this.db
    .collection("projects")
    .doc(projectId)
    .collection<ProjectWorkReport>(
      "workReports", 
      ref => ref.where("invalid", "==", false).orderBy("createdAt", "desc")
    )
    .valueChanges({ idField: "id" });
}

创建方法(注意createdAt):

createProjectWorkReport(projectId: string, workReport: ProjectWorkReport): Promise<DocumentReference> {
  return this.db
    .collection("projects")
    .doc(projectId)
    .collection<ProjectWorkReport>("workReports")
    .add({ ...workReport, createdAt: firebase.firestore.FieldValue.serverTimestamp() });
}

我的订阅(我只记录结果):

this.projectsService.getWorkReportsByProjectId(projectId)
  .pipe(takeUntil(this.destroyed$))
  .subscribe((reports) => {
    console.log(reports);
  });

这是正在记录的内容。因为orderBy("createdAt", "desc"),位置0的元素是新的,但是它的createAt 属性是null,但是如果对DB进行更改或者重新查询,新的结果就是createdAt 通常(如果我再创建一个新的 null)。

我的猜测是 Firestore 独立于文档的创建考虑了时间戳标记,并且订阅在时间戳设置之前触发。

我是不是做错了什么?如果我的猜测是正确的,我可以做些什么来解决?

这种行为可以用 article 来解释。综上,和你猜想的差不多。 serverTimestamps 不会在创建的文档中立即定义,而是在文档创建后由 Firebase 服务器解析,稍有延迟。这导致文档创建和您在时间戳上看到的值之间的差异非常小,此外还有涉及侦听器时看到的 null 值:

Then, when set() is called, the listener fires immediately, before the write hits the server. The SDK doesn’t deliver the token value to the listener. Instead, it simply delivers null (for now), because the final value isn’t known (yet).

解析时间戳后,您就会开始在 Web 控制台中看到它。此行为有两种解决方法,其中之一是使用 snapshotOptions property to provide an instant estimate of the timestamp. The other one is to use the hasPendingWrites property,它可以让您处理如何处理仍未解决的文档。

同一篇文章深入介绍了服务器时间戳的工作原理,并提供了示例代码。