使用Google Firebase登录时重复创建用户,Stripe订阅数据丢失求助
Google登录后Firestore用户订阅数据被覆盖问题
技术栈
- Firebase
- Next.js
- Google 登录
- Firebase Stripe 扩展
Bug复现步骤
- 使用Google账号登录
- 通过Stripe完成订阅,Stripe自动将订阅数据保存至Firestore的
users集合对应文档中 - 退出登录
- 再次使用同一Google账号登录,发现原有订阅信息丢失,用户文档被覆盖
有没有人遇到过类似问题?怀疑是我的登录实现存在问题,以下是相关代码:
Google登录逻辑
const handleGoogleLogin = () => { signInWithPopup(auth, googleProvider) .then(async result => { if (!result.user) return; const { displayName, email, uid, providerData, photoURL, phoneNumber } = result.user; const name = splitName(displayName as string); const providerId = (providerData.length && providerData[0]?.providerId) || ''; const data = { firstName: name?.firstName || '', lastName: name?.lastName || '', email, photoURL, phoneNumber, providerId, }; await updateUser(uid, data); }) .catch(error => { console.log('Google login error: ', error); }); };
用户更新函数
export const updateUser = async (uid: string, data: UpdateUserParams) => { try { if (!uid) { return; } await setDoc(doc(firestore, 'users', uid), { account: { ...data, initials: `${data.firstName[0]}${data.lastName[0]}`, }, }); } catch (error) { console.error('Error updating user: ', error); } };
问题原因
核心问题出在updateUser函数中的setDoc方法:默认情况下,setDoc如果目标文档已经存在,会完全覆盖整个文档。当用户完成订阅后,Stripe扩展会在users文档中添加subscription(或类似字段);而再次登录时调用setDoc,只传入了account字段,导致原有文档中的订阅数据被彻底覆盖删除。
解决方案
修改updateUser函数,使用setDoc的merge选项(推荐),或者改用updateDoc,确保只更新指定字段,保留文档中已有的其他数据:
方案1:使用setDoc的合并选项
export const updateUser = async (uid: string, data: UpdateUserParams) => { try { if (!uid) { return; } const userDoc = doc(firestore, 'users', uid); // merge: true 会保留文档原有字段,仅更新传入的字段 await setDoc(userDoc, { account: { ...data, initials: `${data.firstName[0]}${data.lastName[0]}`, }, }, { merge: true }); } catch (error) { console.error('Error updating user: ', error); } };
方案2:区分创建/更新操作
如果需要更明确的逻辑,可以先判断文档是否存在,新用户创建文档,老用户仅更新字段:
export const updateUser = async (uid: string, data: UpdateUserParams) => { try { if (!uid) { return; } const userDoc = doc(firestore, 'users', uid); const docSnapshot = await getDoc(userDoc); if (docSnapshot.exists()) { // 已有用户,仅更新account字段 await updateDoc(userDoc, { account: { ...data, initials: `${data.firstName[0]}${data.lastName[0]}`, }, }); } else { // 新用户,创建完整文档,可初始化订阅字段 await setDoc(userDoc, { account: { ...data, initials: `${data.firstName[0]}${data.lastName[0]}`, }, subscription: null }); } } catch (error) { console.error('Error updating user: ', error); } };
这样修改后,再次登录时只会更新用户的账号信息,不会覆盖Stripe保存的订阅数据。
内容的提问来源于stack exchange,提问作者Mark James
相关产品推荐
相关产品推荐

