Firestore如何通过事务实现顺序创建集合并更新文档保障数据一致性
Firestore 多写入操作一致性解决方案
方案1:使用批量写入(Batch Writes,推荐当前场景使用)
你的场景所有操作均为写入,没有前置读取校验的需求,用Batch即可实现原子性,所有操作要么全部成功要么全部失败,完全满足你的一致性要求。
实现逻辑:Firestore的文档ID可在客户端预生成,无需先写入服务端,因此你可以提前拿到spaceId再执行所有写入操作。
示例代码:
const userId = "someUserId"; // 预生成空间文档引用,提前拿到spaceId,无需发起服务端请求 const spaceRef = db.collection("spaces").doc(); const spaceId = spaceRef.id; // 初始化批量写入对象 const batch = db.batch(); // 1. 写入空间基础数据 batch.set(spaceRef, { name: "SomeName" }); // 2. 写入用户侧的空间关联数据 const userSpaceRef = db.collection("users").doc(userId).collection("spaces").doc(spaceId); batch.set(userSpaceRef, { some: "data" }); // 3. 写入空间的成员数据 const memberRef = spaceRef.collection("members").doc(userId); batch.set(memberRef, { role: "OWNER" }); // 提交批量操作,原子性执行 await batch.commit();
方案2:使用事务(适合需要前置读取校验的场景)
如果你后续需要增加读取逻辑(比如先校验用户是否存在、用户是否有创建空间的权限等),可以用事务实现,同样基于预生成spaceId的逻辑即可,不需要先写入空间再拿ID。
示例代码:
const userId = "someUserId"; // 预生成空间引用和ID const spaceRef = db.collection("spaces").doc(); const spaceId = spaceRef.id; const userRef = db.collection("users").doc(userId); await db.runTransaction(async (t) => { // 如有需要可在此处执行读取操作,比如校验用户是否存在 const userDoc = await t.get(userRef); if (!userDoc.exists) { throw new Error("用户不存在,无法创建空间"); } // 执行所有写入操作 t.set(spaceRef, { name: "SomeName" }); t.set(userRef.collection("spaces").doc(spaceId), { some: "data" }); t.set(spaceRef.collection("members").doc(userId), { role: "OWNER" }); });
实现说明
- Firestore的自动文档ID生成逻辑在客户端完成,生成的ID全局唯一,不会出现冲突,预生成ID再写入的逻辑和调用
add()生成ID的逻辑完全等价。 - 两种方案都能保证所有写入操作的原子性,不会出现部分成功部分失败的情况,完全满足你对数据一致性的要求。
- 批量写入最大支持500个操作,超出上限可拆分多个Batch或者改用事务。
内容的提问来源于stack exchange,提问作者mixalbl4
相关产品推荐
相关产品推荐

