Shaun
Shaun

Reputation: 151

Firebase normal query in a transaction

Some questions regarding Transaction in Firebase.

Transaction documentation says read before write. Let's say if I t.get() 2 documents in a db.runTransaction(t) in the beginning. Then mid-way in the runTransaction code block, I t.update() both documents. Does it mean that if there are any changes in the 2 documents beyond the t.update(), the runTransaction will retry?

Also, if I do a normal document get() within the transaction code block, will changes in the document after the get() within the transaction cause the transaction to retry?

db.runTransaction(async t => {
   const snapshot1 = await t.get(db.collection('col1').doc('doc1'));
   const snapshot2 = await t.get(db.collection('col2').doc('doc2'));
   const snapshot3 = await db.collection('col3').doc('doc3').get();

   // changes in col1.doc1 or col2.doc2 will trigger retry
   // QUESTION: Will changes in col3.doc3 trigger a retry?
   doSomething(snapshot1);
   doSomething(snapshot2);

   await Promise.all([
       t.update(snapshot1.ref, { field1: 'a' }),
       t.update(snapshot2.ref, { field1: 'b' })
   ]);
   // QUESTION: will changes in col1.doc1 or col2.doc2 externally beyond here trigger a retry

   doSomething(snapshot3);
});

Appreciate all your expert views/insights. Thanks.

Upvotes: 1

Views: 438

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83191

Does it mean that if there are any changes in the 2 documents beyond (before) the t.update(), the Transaction will retry?

Yes, as explained in the doc: "In the case of a concurrent edit, Cloud Firestore runs the entire transaction again"

Also, if I do a normal document get() within the transaction code block, will changes in the document after the get() within the transaction cause the transaction to retry?

You should not fetch a document with a "normal" get() but use the transaction's get() method (i.e. t.get()). With a normal get() the document will not be "included" in the transaction.


In addition, note that you don't need to do:

await Promise.all([
    t.update(snapshot1.ref, { field1: 'a' }),
    t.update(snapshot2.ref, { field1: 'b' })
]);

because t.update() is not asynchronous. It does not return a Promise but the Transaction instance itself, and can be used for chaining method calls like:

t.update(snapshot1.ref, { field1: 'a' }).update(snapshot2.ref, { field1: 'b' })

Note that it's similar for set() and delete().

Upvotes: 2

Related Questions