如何配置Firestore时间戳输出以解决JSON序列化错误?
Firestore Timestamp序列化问题解决方案
问题场景
你在Firestore中存储的文档包含Timestamp类型字段,日志输出如下:
{ my_timestamp: Timestamp { seconds: 1676783325, nanoseconds: 209000000 }, product_name: 'Android' }
通过以下代码读取文档时:
... const result = [] productDocs.forEach((productDoc: DocumentData) => { result.push({ id: productDoc.id, ...productDoc.data() }) }) return result ...
遇到Next.js getStaticProps的序列化错误:
Server Error Error: Error serializing `.productDoc[0].my_timestamp` returned from `getStaticProps` in "/[pid]". Reason: `object` ("[object Object]") cannot be serialized as JSON. Please only return JSON serializable data types.
问题原因
Firestore的Timestamp是自定义对象,不属于JSON原生支持的序列化类型(字符串、数字、数组、普通对象等),而Next.js的getStaticProps要求返回的数据必须能被序列化为JSON,因此直接返回包含Timestamp的对象会报错。
解决方案
1. 简化手动转换逻辑
你当前手动遍历转换的思路是正确的,但可以通过map和Object.fromEntries简化代码,无需繁琐的forEach:
const result = productDocs.map((productDoc) => { const rawData = productDoc.data(); // 遍历所有字段,自动转换Timestamp const processedData = Object.fromEntries( Object.entries(rawData).map(([key, value]) => { // 判断是否为Timestamp对象(根据结构或instanceof) if (value instanceof Timestamp || (value?.seconds && value?.nanoseconds)) { // 转成JS Date对象(会自动序列化为ISO字符串),或用value.toJSON()直接得到字符串 return [key, value.toDate()]; } return [key, value]; }) ); return { id: productDoc.id, ...processedData }; });
2. 使用Firestore数据转换器(推荐)
通过withConverter定义全局转换器,实现一次配置、自动处理所有文档的Timestamp转换,避免重复编写转换逻辑:
首先定义转换器:
import { Timestamp, DocumentData, QueryDocumentSnapshot } from "firebase/firestore"; const productConverter = { // 写入Firestore时的转换(如果不需要修改可以直接返回原对象) toFirestore: (product: DocumentData) => product, // 读取Firestore时的转换 fromFirestore: (snapshot: QueryDocumentSnapshot) => { const rawData = snapshot.data(); const processedData = Object.fromEntries( Object.entries(rawData).map(([key, value]) => { if (value instanceof Timestamp) { return [key, value.toDate()]; } return [key, value]; }) ); return { id: snapshot.id, ...processedData }; } };
然后读取文档时应用转换器:
// 假设db是你的Firestore实例 const productQuery = db.collection('products').withConverter(productConverter); const productDocs = await productQuery.get(); const result = productDocs.docs.map(doc => doc.data());
关于"无需手动处理"的说明
目前Firestore官方确实没有提供全局自动转换Timestamp的配置项,因为Timestamp保留了纳秒级精度(JS Date仅支持毫秒级),直接转换会丢失部分信息。如果你的业务不需要纳秒精度,上述两种方法是最常用的解决方案;如果需要保留纳秒,可以将Timestamp转换为包含seconds和nanoseconds的普通对象(同样可被JSON序列化)。
内容的提问来源于stack exchange,提问作者engineer-x
相关产品推荐
相关产品推荐

