Node.js中Cloud Firestore自定义对象转换报错:snapshot.data不是函数
问题分析与解决方案
你遇到的错误核心原因是使用withConverter后,get()返回的结果已经是转换后的自定义对象,而非Firebase的文档快照,所以调用snapshot.data()自然会报错——你的LogEntryUser类并没有data()方法。另外,你的代码存在冗余的数据库请求:外层已经获取了Users集合的所有文档快照,完全没必要再对每个文档ID重新发起一次get请求。
错误根源拆解
看这段引发问题的代码:
db.collection("Users").doc(doc.id).withConverter(logConverterUser).get().then(function(snapshot){ // 转换为日志对象并读取token logentryuser = snapshot.data(); var registrationToken = logentryuser.getToken(); });
当你给文档引用加上withConverter(logConverterUser)后,get()返回的Promise会直接解析为LogEntryUser实例,而不是QueryDocumentSnapshot。所以这里的snapshot本身就是你的自定义对象,再调用.data()当然会触发TypeError。
修正后的代码
我们可以直接在集合查询时就应用转换器,一次性获取所有转换后的对象,同时用async/await简化异步逻辑,避免回调地狱:
// 定义用户日志条目类 class LogEntryUser { constructor(token, email){ this.token = token; this.email = email; } getToken(){ return this.token; } getEmail(){ return this.email; } } // Firebase数据转换器 const logConverterUser = { toFirestore: function(logentryuser){ return { token: logentryuser.token, email: logentryuser.email } }, fromFirestore: function(snapshot, options){ const data = snapshot.data(options); return new LogEntryUser(data.token, data.email) } }; // 正确的读取逻辑 async function fetchUsers() { try { // 直接在集合上应用转换器 const querySnapshot = await db.collection("Users").withConverter(logConverterUser).get(); querySnapshot.forEach((doc) => { // doc.data() 已经是 LogEntryUser 实例 const logentryuser = doc.data(); const registrationToken = logentryuser.getToken(); console.log("用户Token:", registrationToken); }); } catch (error) { console.error("读取用户数据失败:", error); } } // 调用函数 fetchUsers();
额外注意事项
- 避免冗余请求:外层
get()已经拿到了所有文档的快照,不要再重复发起单个文档的get()请求,这会浪费数据库资源并增加延迟。 - 处理异步错误:一定要用
try/catch或者.catch()捕获Promise的异常,避免出现UnhandledPromiseRejectionWarning。 - 变量声明:你的原代码中
logentryuser没有用let或const声明,会变成全局变量,这是不良实践,记得加上变量声明。
内容的提问来源于stack exchange,提问作者keved
相关产品推荐
相关产品推荐

