Stay organized with collectionsSave and categorize content based on your preferences.
Transactions and batched writes
Firestore supports atomic operations for reading
and writing data. In a set of atomic operations, either all of the operations
succeed, or none of them are applied. There are two types of atomic operations
in Firestore:
Transactions: atransactionis a set of
read and write operations on one or more documents.
Batched Writes: abatched writeis a set of
write operations on one or more documents.
Updating data with transactions
Using the Firestore client libraries, you can group multiple
operations into a single transaction. Transactions are useful when you want to
update a field's value based on its current value, or the value of some other
field.
A transaction consists of any number ofget()operations followed by any number of write operations such asset(),update(), ordelete(). In the case of a concurrent edit,
Firestore runs the entire transaction again. For example, if a
transaction reads documents and another client modifies any of those documents,
Firestore retries the transaction. This feature ensures that the
transaction runs on up-to-date and consistent data.
Transactions never partially
apply writes. All writes execute at the end of a successful transaction.
When using transactions, note that:
Read operations must come before write operations.
A function calling a transaction (transaction function) might run
more than once if a concurrent edit affects a document that the transaction
reads.
Transaction functions should not directly modify application state.
Transactions will fail when the client is offline.
The following example shows how to create and run a transaction:
Web version 9
import{runTransaction}from"firebase/firestore";try{awaitrunTransaction(db,async(transaction)=>{constsfDoc=awaittransaction.get(sfDocRef);if(!sfDoc.exists()){throw"Document does not exist!";}constnewPopulation=sfDoc.data().population+1;transaction.update(sfDocRef,{population:newPopulation});});console.log("Transaction successfully committed!");}catch(e){console.log("Transaction failed: ",e);}
// Create a reference to the SF doc.varsfDocRef=db.collection("cities").doc("SF");// Uncomment to initialize the doc.// sfDocRef.set({ population: 0 });returndb.runTransaction((transaction)=>{// This code may get re-run multiple times if there are conflicts.returntransaction.get(sfDocRef).then((sfDoc)=>{if(!sfDoc.exists){throw"Document does not exist!";}// Add one person to the city population.// Note: this could be done without a transaction// by updating the population using FieldValue.increment()varnewPopulation=sfDoc.data().population+1;transaction.update(sfDocRef,{population:newPopulation});});}).then(()=>{console.log("Transaction successfully committed!");}).catch((error)=>{console.log("Transaction failed: ",error);});
Note:This product is not available on watchOS and App Clip targets.
letsfReference=db.collection("cities").document("SF")do{let_=tryawaitdb.runTransaction({(transaction,errorPointer)->Any?inletsfDocument:DocumentSnapshotdo{trysfDocument=transaction.getDocument(sfReference)}catchletfetchErrorasNSError{errorPointer?.pointee=fetchErrorreturnnil}guardletoldPopulation=sfDocument.data()?["population"]as?Intelse{leterror=NSError(domain:"AppErrorDomain",code:-1,userInfo:[NSLocalizedDescriptionKey:"Unable to retrieve population from snapshot\(sfDocument)"])errorPointer?.pointee=errorreturnnil}// Note: this could be done without a transaction// by updating the population using FieldValue.increment()transaction.updateData(["population":oldPopulation+1],forDocument:sfReference)returnnil})print("Transaction successfully committed!")}catch{print("Transaction failed:\(error)")}
Note:This product is not available on watchOS and App Clip targets.
FIRDocumentReference*sfReference=[[self.dbcollectionWithPath:@"cities"]documentWithPath:@"SF"];[self.dbrunTransactionWithBlock:^id(FIRTransaction*transaction,NSError**errorPointer){FIRDocumentSnapshot*sfDocument=[transactiongetDocument:sfReferenceerror:errorPointer];if(*errorPointer!=nil){returnnil;}if(![sfDocument.data[@"population"]isKindOfClass:[NSNumberclass]]){*errorPointer=[NSErrorerrorWithDomain:@"AppErrorDomain"code:-1userInfo:@{NSLocalizedDescriptionKey:@"Unable to retreive population from snapshot"}];returnnil;}NSIntegeroldPopulation=[sfDocument.data[@"population"]integerValue];// Note: this could be done without a transaction// by updating the population using FieldValue.increment()[transactionupdateData:@{@"population":@(oldPopulation+1)}forDocument:sfReference];returnnil;}completion:^(idresult,NSError*error){if(error!=nil){NSLog(@"Transaction failed: %@",error);}else{NSLog(@"Transaction successfully committed!");}}];
valsfDocRef=db.collection("cities").document("SF")db.runTransaction{transaction->valsnapshot=transaction.get(sfDocRef)// Note: this could be done without a transaction// by updating the population using FieldValue.increment()valnewPopulation=snapshot.getDouble("population")!!+1transaction.update(sfDocRef,"population",newPopulation)// Successnull}.addOnSuccessListener{Log.d(TAG,"Transaction success!")}.addOnFailureListener{e->Log.w(TAG,"Transaction failure.",e)}
finalDocumentReferencesfDocRef=db.collection("cities").document("SF");db.runTransaction(newTransaction.Function<Void>(){@OverridepublicVoidapply(@NonNullTransactiontransaction)throwsFirebaseFirestoreException{DocumentSnapshotsnapshot=transaction.get(sfDocRef);// Note: this could be done without a transaction// by updating the population using FieldValue.increment()doublenewPopulation=snapshot.getDouble("population")+1;transaction.update(sfDocRef,"population",newPopulation);// Successreturnnull;}}).addOnSuccessListener(newOnSuccessListener<Void>(){@OverridepublicvoidonSuccess(VoidaVoid){Log.d(TAG,"Transaction success!");}}).addOnFailureListener(newOnFailureListener(){@OverridepublicvoidonFailure(@NonNullExceptione){Log.w(TAG,"Transaction failure.",e);}});
finalsfDocRef=db.collection("cities").doc("SF");db.runTransaction((transaction)async{finalsnapshot=awaittransaction.get(sfDocRef);// Note: this could be done without a transaction// by updating the population using FieldValue.increment()finalnewPopulation=snapshot.get("population")+1;transaction.update(sfDocRef,{"population":newPopulation});}).then((value)=>print("DocumentSnapshot successfully updated!"),onError:(e)=>print("Error updating document$e"),);
// Initialize docfinalDocumentReferencedocRef=db.collection("cities").document("SF");Citycity=newCity("SF");city.setCountry("USA");city.setPopulation(860000L);docRef.set(city).get();// run an asynchronous transactionApiFuture<Void>futureTransaction=db.runTransaction(transaction->{// retrieve document and increment population fieldDocumentSnapshotsnapshot=transaction.get(docRef).get();longoldPopulation=snapshot.getLong("population");transaction.update(docRef,"population",oldPopulation+1);returnnull;});// block on transaction operation using transaction.get()
DocumentReferencesf_doc_ref=db->Collection("cities").Document("SF");db->RunTransaction([sf_doc_ref](Transaction&transaction,std::string&out_error_message)->Error{Errorerror=Error::kErrorOk;DocumentSnapshotsnapshot=transaction.Get(sf_doc_ref,&error,&out_error_message);// Note: this could be done without a transaction by updating the// population using FieldValue::Increment().std::int64_tnew_population=snapshot.Get("population").integer_value()+1;transaction.Update(sf_doc_ref,{{"population", FieldValue::Integer(new_population)}});returnError::kErrorOk;}).OnCompletion([](constFuture<void>&future){if(future.error()==Error::kErrorOk){std::cout<<"Transaction success!"<<std::endl;}else{std::cout<<"Transaction failure: "<<future.error_message()<<std::endl;}});
// Initialize documentconstcityRef=db.collection('cities').doc('SF');awaitcityRef.set({name:'San Francisco',state:'CA',country:'USA',capital:false,population:860000});try{awaitdb.runTransaction(async(t)=>{constdoc=awaitt.get(cityRef);// Add one person to the city population.// Note: this could be done without a transaction// by updating the population using FieldValue.increment()constnewPopulation=doc.data().population+1;t.update(cityRef,{population:newPopulation});});console.log('Transaction success!');}catch(e){console.log('Transaction failure:',e);}
import("context""log""cloud.google.com/go/firestore")funcrunSimpleTransaction(ctxcontext.Context,client*firestore.Client)error{// ...ref:=client.Collection("cities").Doc("SF")err:=client.RunTransaction(ctx,func(ctxcontext.Context,tx*firestore.Transaction)error{doc,err:=tx.Get(ref)// tx.Get, NOT ref.Get!iferr!=nil{returnerr}pop,err:=doc.DataAt("population")iferr!=nil{returnerr}returntx.Set(ref,map[string]interface{}{"population":pop.(int64)+1,},firestore.MergeAll)})iferr!=nil{// Handle any errors appropriately in this section.log.Printf("An error has occurred: %s",err)}returnerr}
city_ref=firestore.doc"#{collection_path}/SF"firestore.transactiondo|tx|new_population=tx.get(city_ref).data[:population]+1puts"New population is#{new_population}."tx.updatecity_ref,{population:new_population}end
Do not modify application state inside of your transaction functions. Doing so
will introduce concurrency issues, because transaction functions can run
multiple times and are not guaranteed to run on the UI thread. Instead, pass
information you need out of your transaction functions. The following example
builds on the previous example to show how to pass information out of a
transaction:
Web version 9
import{doc,runTransaction}from"firebase/firestore";// Create a reference to the SF doc.constsfDocRef=doc(db,"cities","SF");try{constnewPopulation=awaitrunTransaction(db,async(transaction)=>{constsfDoc=awaittransaction.get(sfDocRef);if(!sfDoc.exists()){throw"Document does not exist!";}constnewPop=sfDoc.data().population+1;if(newPop<=1000000){transaction.update(sfDocRef,{population:newPop});returnnewPop;}else{returnPromise.reject("Sorry! Population is too big");}});console.log("Population increased to ",newPopulation);}catch(e){// This will be a "population is too big" error.console.error(e);}
// Create a reference to the SF doc.varsfDocRef=db.collection("cities").doc("SF");db.runTransaction((transaction)=>{returntransaction.get(sfDocRef).then((sfDoc)=>{if(!sfDoc.exists){throw"Document does not exist!";}varnewPopulation=sfDoc.data().population+1;if(newPopulation<=1000000){transaction.update(sfDocRef,{population:newPopulation});returnnewPopulation;}else{returnPromise.reject("Sorry! Population is too big.");}});}).then((newPopulation)=>{console.log("Population increased to ",newPopulation);}).catch((err)=>{// This will be an "population is too big" error.console.error(err);});
Note:This product is not available on watchOS and App Clip targets.
letsfReference=db.collection("cities").document("SF")do{letobject=tryawaitdb.runTransaction({(transaction,errorPointer)->Any?inletsfDocument:DocumentSnapshotdo{trysfDocument=transaction.getDocument(sfReference)}catchletfetchErrorasNSError{errorPointer?.pointee=fetchErrorreturnnil}guardletoldPopulation=sfDocument.data()?["population"]as?Intelse{leterror=NSError(domain:"AppErrorDomain",code:-1,userInfo:[NSLocalizedDescriptionKey:"Unable to retrieve population from snapshot\(sfDocument)"])errorPointer?.pointee=errorreturnnil}// Note: this could be done without a transaction// by updating the population using FieldValue.increment()letnewPopulation=oldPopulation+1guardnewPopulation<=1000000else{leterror=NSError(domain:"AppErrorDomain",code:-2,userInfo:[NSLocalizedDescriptionKey:"Population\(newPopulation)too big"])errorPointer?.pointee=errorreturnnil}transaction.updateData(["population":newPopulation],forDocument:sfReference)returnnewPopulation})print("Population increased to\(object!)")}catch{print("Error updating population:\(error)")}
Note:This product is not available on watchOS and App Clip targets.
FIRDocumentReference*sfReference=[[self.dbcollectionWithPath:@"cities"]documentWithPath:@"SF"];[self.dbrunTransactionWithBlock:^id(FIRTransaction*transaction,NSError**errorPointer){FIRDocumentSnapshot*sfDocument=[transactiongetDocument:sfReferenceerror:errorPointer];if(*errorPointer!=nil){returnnil;}if(![sfDocument.data[@"population"]isKindOfClass:[NSNumberclass]]){*errorPointer=[NSErrorerrorWithDomain:@"AppErrorDomain"code:-1userInfo:@{NSLocalizedDescriptionKey:@"Unable to retreive population from snapshot"}];returnnil;}NSIntegerpopulation=[sfDocument.data[@"population"]integerValue];population++;if(population>=1000000){*errorPointer=[NSErrorerrorWithDomain:@"AppErrorDomain"code:-2userInfo:@{NSLocalizedDescriptionKey:@"Population too big"}];return@(population);}[transactionupdateData:@{@"population":@(population)}forDocument:sfReference];returnnil;}completion:^(idresult,NSError*error){if(error!=nil){NSLog(@"Transaction failed: %@",error);}else{NSLog(@"Population increased to %@",result);}}];
valsfDocRef=db.collection("cities").document("SF")db.runTransaction{transaction->valsnapshot=transaction.get(sfDocRef)valnewPopulation=snapshot.getDouble("population")!!+1if(newPopulation<=1000000){transaction.update(sfDocRef,"population",newPopulation)newPopulation}else{throwFirebaseFirestoreException("Population too high",FirebaseFirestoreException.Code.ABORTED,)}}.addOnSuccessListener{result->Log.d(TAG,"Transaction success:$result")}.addOnFailureListener{e->Log.w(TAG,"Transaction failure.",e)}
finalDocumentReferencedocRef=db.collection("cities").document("SF");ApiFuture<String>futureTransaction=db.runTransaction(transaction->{DocumentSnapshotsnapshot=transaction.get(docRef).get();LongnewPopulation=snapshot.getLong("population")+1;// conditionally update based on current populationif(newPopulation<=1000000L){transaction.update(docRef,"population",newPopulation);return"Population increased to "+newPopulation;}else{thrownewException("Sorry! Population is too big.");}});// Print information retrieved from transactionSystem.out.println(futureTransaction.get());
transaction=db.transaction()city_ref=db.collection("cities").document("SF")@firestore.transactionaldefupdate_in_transaction(transaction,city_ref):snapshot=city_ref.get(transaction=transaction)new_population=snapshot.get("population")+1ifnew_population<1000000:transaction.update(city_ref,{"population":new_population})returnTrueelse:returnFalseresult=update_in_transaction(transaction,city_ref)ifresult:print("Population updated")else:print("Sorry! Population is too big.")
transaction=db.transaction()city_ref=db.collection("cities").document("SF")@firestore.async_transactionalasyncdefupdate_in_transaction(transaction,city_ref):snapshot=awaitcity_ref.get(transaction=transaction)new_population=snapshot.get("population")+1ifnew_population<1000000:transaction.update(city_ref,{"population":new_population})returnTrueelse:returnFalseresult=awaitupdate_in_transaction(transaction,city_ref)ifresult:print("Population updated")else:print("Sorry! Population is too big.")
constcityRef=db.collection('cities').doc('SF');try{constres=awaitdb.runTransaction(asynct=>{constdoc=awaitt.get(cityRef);constnewPopulation=doc.data().population+1;if(newPopulation<=1000000){awaitt.update(cityRef,{population:newPopulation});return`Population increased to${newPopulation}`;}else{throw'Sorry! Population is too big.';}});console.log('Transaction success',res);}catch(e){console.log('Transaction failure:',e);}
import("context""errors""log""cloud.google.com/go/firestore")funcinfoTransaction(ctxcontext.Context,client*firestore.Client)(int64,error){varupdatedPopint64ref:=client.Collection("cities").Doc("SF")err:=client.RunTransaction(ctx,func(ctxcontext.Context,tx*firestore.Transaction)error{doc,err:=tx.Get(ref)iferr!=nil{returnerr}pop,err:=doc.DataAt("population")iferr!=nil{returnerr}newpop:=pop.(int64)+1ifnewpop<=1000000{err:=tx.Set(ref,map[string]interface{}{"population":newpop,},firestore.MergeAll)iferr==nil{updatedPop=newpop}returnerr}returnerrors.New("population is too big")})iferr!=nil{// Handle any errors in an appropriate way, such as returning them.log.Printf("An error has occurred: %s",err)}returnupdatedPop,err}
DocumentReferencecityRef=db.Collection("cities").Document("SF");db.RunTransactionAsync(transaction=>{returntransaction.GetSnapshotAsync(cityRef).ContinueWith((task)=>{longnewPopulation=task.Result.GetValue<long>("Population")+1;if(newPopulation<=1000000){Dictionary<string,object>updates=newDictionary<string,object>{{"Population",newPopulation}};transaction.Update(cityRef,updates);returntrue;}else{returnfalse;}});}).ContinueWith((transactionResultTask)=>{if(transactionResultTask.Result){Console.WriteLine("Population updated successfully.");}else{Console.WriteLine("Sorry! Population is too big.");}});
C#
DocumentReferencecityRef=db.Collection("cities").Document("SF");booltransactionResult=awaitdb.RunTransactionAsync(asynctransaction=>{DocumentSnapshotsnapshot=awaittransaction.GetSnapshotAsync(cityRef);longnewPopulation=snapshot.GetValue<long>("Population")+1;if(newPopulation<=1000000){Dictionary<string,object>updates=newDictionary<string,object>{{"Population",newPopulation}};transaction.Update(cityRef,updates);returntrue;}else{returnfalse;}});if(transactionResult){Console.WriteLine("Population updated successfully.");}else{Console.WriteLine("Sorry! Population is too big.");}
city_ref=firestore.doc"#{collection_path}/SF"updated=firestore.transactiondo|tx|new_population=tx.get(city_ref).data[:population]+1ifnew_population<1_000_000tx.updatecity_ref,{population:new_population}trueendendifupdatedputs"Population updated!"elseputs"Sorry! Population is too big."end
The transaction contains read operations after write operations.
Read operations must always come before any write operations.
The transaction read a document that was modified outside of the transaction.
In this case, the transaction automatically runs again. The
transaction is retried a finite number of times.
The transaction exceeded the maximum request size of 10 MiB.
Transaction size depends on the sizes of documents and index entries
modified by the transaction. For a delete operation, this includes the size
of the target document and the sizes of the index entries deleted in
response to the operation.
The transaction exceeded the lock deadline (20 seconds). Firestore automatically releases locks if a transaction cannot complete in time.
A failed transaction returns an error and does not write anything to the
database. You do not need to roll back the transaction; Firestore
does this automatically.
Batched writes
If you do not need to read any documents in your operation set, you can execute
multiple write operations as a single batch that contains any combination ofset(),update(), ordelete()operations.
Each operation in the batch counts separately towards your
Firestore usage. A batch of writes completes
atomically and can write to multiple documents. The following
example shows how to build and commit a write batch:
Web version 9
import{writeBatch,doc}from"firebase/firestore";// Get a new write batchconstbatch=writeBatch(db);// Set the value of 'NYC'constnycRef=doc(db,"cities","NYC");batch.set(nycRef,{name:"New York City"});// Update the population of 'SF'constsfRef=doc(db,"cities","SF");batch.update(sfRef,{"population":1000000});// Delete the city 'LA'constlaRef=doc(db,"cities","LA");batch.delete(laRef);// Commit the batchawaitbatch.commit();
// Get a new write batchvarbatch=db.batch();// Set the value of 'NYC'varnycRef=db.collection("cities").doc("NYC");batch.set(nycRef,{name:"New York City"});// Update the population of 'SF'varsfRef=db.collection("cities").doc("SF");batch.update(sfRef,{"population":1000000});// Delete the city 'LA'varlaRef=db.collection("cities").doc("LA");batch.delete(laRef);// Commit the batchbatch.commit().then(()=>{// ...});
Note:This product is not available on watchOS and App Clip targets.
// Get new write batchletbatch=db.batch()// Set the value of 'NYC'letnycRef=db.collection("cities").document("NYC")batch.setData([:],forDocument:nycRef)// Update the population of 'SF'letsfRef=db.collection("cities").document("SF")batch.updateData(["population":1000000],forDocument:sfRef)// Delete the city 'LA'letlaRef=db.collection("cities").document("LA")batch.deleteDocument(laRef)// Commit the batchdo{tryawaitbatch.commit()print("Batch write succeeded.")}catch{print("Error writing batch:\(error)")}
Note:This product is not available on watchOS and App Clip targets.
// Get new write batchFIRWriteBatch*batch=[self.dbbatch];// Set the value of 'NYC'FIRDocumentReference*nycRef=[[self.dbcollectionWithPath:@"cities"]documentWithPath:@"NYC"];[batchsetData:@{}forDocument:nycRef];// Update the population of 'SF'FIRDocumentReference*sfRef=[[self.dbcollectionWithPath:@"cities"]documentWithPath:@"SF"];[batchupdateData:@{@"population":@1000000}forDocument:sfRef];// Delete the city 'LA'FIRDocumentReference*laRef=[[self.dbcollectionWithPath:@"cities"]documentWithPath:@"LA"];[batchdeleteDocument:laRef];// Commit the batch[batchcommitWithCompletion:^(NSError*_Nullableerror){if(error!=nil){NSLog(@"Error writing batch %@",error);}else{NSLog(@"Batch write succeeded.");}}];
valnycRef=db.collection("cities").document("NYC")valsfRef=db.collection("cities").document("SF")vallaRef=db.collection("cities").document("LA")// Get a new write batch and commit all write operationsdb.runBatch{batch->// Set the value of 'NYC'batch.set(nycRef,City())// Update the population of 'SF'batch.update(sfRef,"population",1000000L)// Delete the city 'LA'batch.delete(laRef)}.addOnCompleteListener{// ...}
// Get a new write batchWriteBatchbatch=db.batch();// Set the value of 'NYC'DocumentReferencenycRef=db.collection("cities").document("NYC");batch.set(nycRef,newCity());// Update the population of 'SF'DocumentReferencesfRef=db.collection("cities").document("SF");batch.update(sfRef,"population",1000000L);// Delete the city 'LA'DocumentReferencelaRef=db.collection("cities").document("LA");batch.delete(laRef);// Commit the batchbatch.commit().addOnCompleteListener(newOnCompleteListener<Void>(){@OverridepublicvoidonComplete(@NonNullTask<Void>task){// ...}});
// Get a new write batchfinalbatch=db.batch();// Set the value of 'NYC'varnycRef=db.collection("cities").doc("NYC");batch.set(nycRef,{"name":"New York City"});// Update the population of 'SF'varsfRef=db.collection("cities").doc("SF");batch.update(sfRef,{"population":1000000});// Delete the city 'LA'varlaRef=db.collection("cities").doc("LA");batch.delete(laRef);// Commit the batchbatch.commit().then((_){// ...});
// Get a new write batchWriteBatchbatch=db.batch();// Set the value of 'NYC'DocumentReferencenycRef=db.collection("cities").document("NYC");batch.set(nycRef,newCity());// Update the population of 'SF'DocumentReferencesfRef=db.collection("cities").document("SF");batch.update(sfRef,"population",1000000L);// Delete the city 'LA'DocumentReferencelaRef=db.collection("cities").document("LA");batch.delete(laRef);// asynchronously commit the batchApiFuture<List<WriteResult>>future=batch.commit();// ...// future.get() blocks on batch commit operationfor(WriteResultresult:future.get()){System.out.println("Update time : "+result.getUpdateTime());}
batch=db.batch()# Set the data for NYCnyc_ref=db.collection("cities").document("NYC")batch.set(nyc_ref,{"name":"New York City"})# Update the population for SFsf_ref=db.collection("cities").document("SF")batch.update(sf_ref,{"population":1000000})# Delete DENden_ref=db.collection("cities").document("DEN")batch.delete(den_ref)# Commit the batchbatch.commit()
batch=db.batch()# Set the data for NYCnyc_ref=db.collection("cities").document("NYC")batch.set(nyc_ref,{"name":"New York City"})# Update the population for SFsf_ref=db.collection("cities").document("SF")batch.update(sf_ref,{"population":1000000})# Delete DENden_ref=db.collection("cities").document("DEN")batch.delete(den_ref)# Commit the batchawaitbatch.commit()
// Get a new write batchWriteBatchbatch=db->batch();// Set the value of 'NYC'DocumentReferencenyc_ref=db->Collection("cities").Document("NYC");batch.Set(nyc_ref,{});// Update the population of 'SF'DocumentReferencesf_ref=db->Collection("cities").Document("SF");batch.Update(sf_ref,{{"population", FieldValue::Integer(1000000)}});// Delete the city 'LA'DocumentReferencela_ref=db->Collection("cities").Document("LA");batch.Delete(la_ref);// Commit the batchbatch.Commit().OnCompletion([](constFuture<void>&future){if(future.error()==Error::kErrorOk){std::cout<<"Write batch success!"<<std::endl;}else{std::cout<<"Write batch failure: "<<future.error_message()<<std::endl;}});
// Get a new write batchconstbatch=db.batch();// Set the value of 'NYC'constnycRef=db.collection('cities').doc('NYC');batch.set(nycRef,{name:'New York City'});// Update the population of 'SF'constsfRef=db.collection('cities').doc('SF');batch.update(sfRef,{population:1000000});// Delete the city 'LA'constlaRef=db.collection('cities').doc('LA');batch.delete(laRef);// Commit the batchawaitbatch.commit();
import("context""log""cloud.google.com/go/firestore")funcbatchWrite(ctxcontext.Context,client*firestore.Client)error{// Get a new write batch.batch:=client.Batch()// Set the value of "NYC".nycRef:=client.Collection("cities").Doc("NYC")batch.Set(nycRef,map[string]interface{}{"name":"New York City",})// Update the population of "SF".sfRef:=client.Collection("cities").Doc("SF")batch.Set(sfRef,map[string]interface{}{"population":1000000,},firestore.MergeAll)// Delete the city "LA".laRef:=client.Collection("cities").Doc("LA")batch.Delete(laRef)// Commit the batch._,err:=batch.Commit(ctx)iferr!=nil{// Handle any errors in an appropriate way, such as returning them.log.Printf("An error has occurred: %s",err)}returnerr}
$batch = $db->batch();# Set the data for NYC$nycRef = $db->collection('samples/php/cities')->document('NYC');$batch->set($nycRef, ['name' => 'New York City']);# Update the population for SF$sfRef = $db->collection('samples/php/cities')->document('SF');$batch->update($sfRef, [['path' => 'population', 'value' => 1000000]]);# Delete LA$laRef = $db->collection('samples/php/cities')->document('LA');$batch->delete($laRef);# Commit the batch$batch->commit();
WriteBatchbatch=db.StartBatch();// Set the data for NYCDocumentReferencenycRef=db.Collection("cities").Document("NYC");Dictionary<string,object>nycData=newDictionary<string,object>{{"name","New York City"}};batch.Set(nycRef,nycData);// Update the population for SFDocumentReferencesfRef=db.Collection("cities").Document("SF");Dictionary<string,object>updates=newDictionary<string,object>{{"Population",1000000}};batch.Update(sfRef,updates);// Delete LADocumentReferencelaRef=db.Collection("cities").Document("LA");batch.Delete(laRef);// Commit the batchbatch.CommitAsync();
C#
WriteBatchbatch=db.StartBatch();// Set the data for NYCDocumentReferencenycRef=db.Collection("cities").Document("NYC");Dictionary<string,object>nycData=newDictionary<string,object>{{"name","New York City"}};batch.Set(nycRef,nycData);// Update the population for SFDocumentReferencesfRef=db.Collection("cities").Document("SF");Dictionary<string,object>updates=newDictionary<string,object>{{"Population",1000000}};batch.Update(sfRef,updates);// Delete LADocumentReferencelaRef=db.Collection("cities").Document("LA");batch.Delete(laRef);// Commit the batchawaitbatch.CommitAsync();
firestore.batchdo|b|# Set the data for NYCb.set"#{collection_path}/NYC",{name:"New York City"}# Update the population for SFb.update"#{collection_path}/SF",{population:1_000_000}# Delete LAb.delete"#{collection_path}/LA"end
Like transactions, batched writes are atomic. Unlike transactions, batched
writes do not need to ensure that read documents remain un-modified which leads
to fewer failure cases. They are not subject to retries or
to failures from too many retries. Batched writes execute even when the
user's device is offline.
A batched write with hundreds of documents might require many index updates
and might exceed the limit on transaction size. In this case, reduce the number of
documents per batch. To write a large number of documents, consider using a
bulk writer or parallelized individual writes instead.
Data validation for atomic operations
For mobile/web client libraries, you can validate data usingFirestore Security Rules. You can ensure that related documents are
always updated atomically and always as part of a transaction or batched write.
Use thegetAfter()security rule function to access and validate
the state of a document after a set of operations completes butbeforeFirestore commits the operations.
For example, imagine that the database for thecitiesexample also contains acountriescollection. Eachcountrydocument uses alast_updatedfield to
keep track of the last time any city related to that country was updated. The
following security rules require that an update to acitydocument must also
atomically update the related country'slast_updatedfield:
In security rules for transactions or batched writes, there is alimitof 20 document access calls for the entire atomic operation in addition to the
normal 10 call limit for each single document operation in the batch.
For example, consider the following rules for a chat application:
The snippets below illustrate the number of document access calls used for
a few data access patterns:
//0documentaccesscallsused,becausetherulesevaluationshort-circuits//beforetheexists()callisinvoked.db.collection('user').doc('myuid').get(...);//1documentaccesscallused.Themaximumtotalallowedforthiscall//is10,becauseitisasingledocumentrequest.db.collection('chatroom').doc('mygroup').get(...);//Initializingawritebatch...varbatch=db.batch();//2documentaccesscallsused,10allowed.vargroup1Ref=db.collection("chatroom").doc("group1");batch.set(group1Ref,{msg:"Hello, from Admin!"});//1documentaccesscallused,10allowed.varnewUserRef=db.collection("users").doc("newuser");batch.update(newUserRef,{"lastSignedIn":newDate()});//1documentaccesscallused,10allowed.varremovedAdminRef=db.collection("admin").doc("otheruser");batch.delete(removedAdminRef);//Thebatchusedatotalof2+1+1=4documentaccesscalls,outofatotal//20allowed.batch.commit();
For more information on how to resolve latency issues caused by large writes and batched writes, errors due to contention from overlapping transactions, and other issues consider checking out thetroubleshooting page.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-09-04 UTC."],[],[],null,[]]