Firestore集合订阅时新增文档的serverTimestamp字段返回null如何解决
原因说明
你的猜测完全正确,该现象属于Firestore的预期正常行为,不属于操作不当:
Firestore为了支持离线可用特性,写入文档时会先在本地生成缓存快照,立刻触发订阅通知,此时serverTimestamp标记还未经过服务端计算返回,默认会返回null;等服务端写入完成、真实时间戳同步回本地后,会再次触发订阅通知,此时createdAt就会显示为正确值。
可行修复方案
方案1:开启服务端时间戳预估(最常用)
在valueChanges的配置项中添加serverTimestamps: "estimate"规则,首次本地缓存通知时会自动返回本地预估的时间戳,不会出现null,后续服务端返回真实时间后会自动更新为准确值。
修改后的查询代码如下:
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", serverTimestamps: "estimate" }); }
方案2:过滤未完成同步的文档
如果业务要求必须使用服务端生成的准确时间、不接受预估时间,可以改用snapshotChanges获取文档元数据,过滤掉还处于同步中状态的文档,只有服务端写入完成后才会返回给订阅层:
getWorkReportsByProjectId(projectId: string): Observable<ProjectWorkReport[]> { return this.db .collection("projects") .doc(projectId) .collection<ProjectWorkReport>( "workReports", ref => ref.where("invalid", "==", false).orderBy("createdAt", "desc") ) .snapshotChanges() .pipe( map(snapshots => snapshots // 过滤本地未同步完成的文档 .filter(snap => !snap.payload.doc.metadata.hasPendingWrites) .map(snap => { const data = snap.payload.doc.data(); return { id: snap.payload.doc.id, ...data }; }) ) ); }
该方案的缺点是新文档的出现会有几十到几百毫秒的延迟,具体取决于网络状况。
方案3:客户端生成时间戳
如果业务对时间精度要求不高,可以放弃使用服务端时间戳,创建文档时直接用本地时间生成:
createProjectWorkReport(projectId: string, workReport: ProjectWorkReport): Promise<DocumentReference> { return this.db .collection("projects") .doc(projectId) .collection<ProjectWorkReport>("workReports") .add({ ...workReport, createdAt: new Date() }); }
该方案的缺点是如果用户设备时间不准,会导致生成的时间存在误差。
内容的提问来源于stack exchange,提问作者MarksASP
相关产品推荐
相关产品推荐

