如何在Firebase事务中通过双循环实现先读后写
Firestore事务循环读写报错解决方案
问题描述
执行Firestore事务时遇到报错:
Transactions require all reads to be executed before all writes.
原实现代码:
List<QueryDocumentSnapshot> localList2 = [] ; // 列表内包含5个文档 FirebaseFirestore.instance.runTransaction((transaction) async { for (var element in localList2) { DocumentReference userDoc= FirebaseFirestore.instance.collection("users").doc(element.get('userId')); DocumentSnapshot chick = await transaction.get(userDoc); if(chick.exists){ transaction.update(element.get('targetDocRef'),{ 'fieldValue': 'value', }); } } }).then((value){ log.log('done'); }).catchError((error){ log.log(error.toString()); });
问题原因
我觉得你可能误解了报错信息的意思。它要求所有读取操作必须在所有写入操作之前完成。如果循环执行多次,第二次循环的读取操作会在第一次写入之后执行,这就违反了“所有读取先于所有写入”的要求。
正确的做法是:先用一个循环完成所有需要的读取操作,再用另一个循环执行所有写入操作。
修正后的代码
拆分读写循环,先完成所有读取逻辑,再统一执行写入:
List<QueryDocumentSnapshot> localList2 = [] ; // 列表内包含5个文档 FirebaseFirestore.instance.runTransaction((transaction) async { // 第一步:遍历读取所有用户文档,收集需要更新的目标文档 final List<DocumentReference> docsToUpdate = []; for (final element in localList2) { final DocumentReference userDoc = FirebaseFirestore.instance.collection("users").doc(element.get('userId')); final DocumentSnapshot userSnapshot = await transaction.get(userDoc); if (userSnapshot.exists) { docsToUpdate.add(element.get('targetDocRef')); } } // 第二步:统一更新所有目标文档 for (final docRef in docsToUpdate) { transaction.update(docRef, { 'fieldValue': 'value', }); } }).then((value) { log.log('done'); }).catchError((error) { log.log(error.toString()); });
逻辑说明
- 第一个循环仅负责读取用户文档,判断存在后记录需要更新的目标文档引用,全程不执行写入操作,确保所有读取在写入前完成。
- 第二个循环遍历已收集的目标文档引用,统一执行事务更新,完全符合Firestore事务的读写顺序要求。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

