Android中Firestore事务报错:读取的文档必须在事务中写入
解决Firestore事务错误:Every document read in a transaction must also be written
我来帮你搞定这个头疼的问题!你遇到的这个错误是Firestore事务的核心约束导致的:事务中读取的每一个文档,必须在同一个事务内对其执行写入操作(更新、删除、设置都算)。
看你的代码,当documentSnapshot2.exists()为false时,你通过transaction.get(docRef2)读取了这个文档,但之后没有对它做任何写入操作——这直接违反了Firestore的事务规则,所以抛出了那个异常。而你移除判断条件后能成功,是因为不管文档是否存在,你都执行了删除操作(写入),满足了规则。
但你的核心需求是“只有当文档存在时才执行后续操作”,那我们可以这样调整代码,既满足业务逻辑,又符合Firestore的要求:
db.runTransaction(new Transaction.Function<Void>() { @Override public Void apply(Transaction transaction) throws FirebaseFirestoreException { DocumentReference docRef2 = db.collection("ABC").document(mMatchedUserId); DocumentReference ref3 = db.collection("XYZ").document(mCurrentUserId); DocumentReference ref4 = db.collection("XYZ").document(mMatchedUserId); DocumentSnapshot documentSnapshot2 = transaction.get(docRef2); if(documentSnapshot2.exists()) { // 文档存在时执行你需要的操作 transaction.delete(docRef2); transaction.set(ref3, myMap1); transaction.set(ref4, myMap2); } else { // 文档不存在时,执行一个无意义的写入操作满足Firestore规则 // 这里我们先设置一个空文档再删除,相当于没有修改数据库状态 transaction.set(docRef2, new HashMap<>()); transaction.delete(docRef2); } return null; } }).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Log.d(TAG, "Transaction success!"); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.w(TAG, "Transaction failure.", e); } });
为什么这么做?
当文档不存在时,我们先执行set创建一个空文档,再马上删除它——这个操作不会改变数据库的实际状态,但确实对docRef2执行了写入操作,完美满足了Firestore“读了必须写”的规则。
如果你觉得这种方式有点hack,也可以根据业务需求选择其他写入操作:比如给文档设置一个lastChecked字段为当前时间,这样既符合规则,还能记录最后检查的时间,一举两得。
内容的提问来源于stack exchange,提问作者Maverick7
相关产品推荐
相关产品推荐

