- I have an app where I have to verify if a user document still exists in a collection before I start making a series of batched writes on different collections
- The best way to do this is to use a firestore transaction
- I am able to understand the concept of transaction & it works in practice but I have difficulty in understanding which errors would be thrown - So here is an example in my scenario
Case 1: I run transaction. Firestore first reads the document, then conducts the transactional writes/ updates etc then re-checks if the document has been modified. In this case, say another user deletes this document - What does the transaction do? Documentation states it will keep retrying but would it retry if the document itself is deleted?
Case 2: I run transaction. Firstore first reads document. It realizes the document itself does not exist. What happens now?
My question, in both these cases, which errors are called? Should I explicitly check for snapshot.exist and then assign an error pointer? I know these are lots of questions so in summary how are errors handled by a transaction in the case of document delete
I cannot post my code since it is from work and I am barred from doing so. Hence I am posting code from firestore documentation. In the below case what happens when the
- SF document does not exist when the transaction starts
- SF document exist at start but gets deleted by another user before the transaction ends. Again google states it would keep trying but why would it retry when document itself is deleted
let sfReference = db.collection("cities").document("SF")
db.runTransaction({ (transaction, errorPointer) -> Any? in
let sfDocument: DocumentSnapshot
do {
try sfDocument = transaction.getDocument(sfReference)
} catch let fetchError as NSError {
errorPointer?.pointee = fetchError
return nil
}
guard let oldPopulation = sfDocument.data()?["population"] as? Int else {
let error = NSError(
domain: "AppErrorDomain",
code: -1,
userInfo: [
NSLocalizedDescriptionKey: "Unable to retrieve population from snapshot \(sfDocument)"
]
)
errorPointer?.pointee = error
return nil
}
// Note: this could be done without a transaction
// by updating the population using FieldValue.increment()
transaction.updateData(["population": oldPopulation + 1], forDocument: sfReference)
return nil
}) { (object, error) in
if let error = error {
print("Transaction failed: \(error)")
} else {
print("Transaction successfully committed!")
}
}