I'm trying to run a transaction with a variable number of read operations. I put the read () operations before than update ().
Reading the Firestore doc on https://cloud.google.com/firestore/docs/manage-data/transactions
"A transaction consists of any number of get() operations followed by any number of write operations such as set(), update(), or delete()"
And
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 current edit affects a document that the transaction reads.
- Transaction functions should not directly modify application state.
But is not provided an implementation. When I try to run the code below, I get that the transaction function is runned more time and then I obtain an exception. But if I try with only one get all goes OK.
const reservationCol = this.db.firestore.collection('reservations');
return this.db.firestore.runTransaction(t => {
return Promise.all([
t.get(reservationCol.doc('id1')),
t.get(reservationCol.doc(('id2')))]
).then((responses) => {
let found = false;
responses.forEach(resp => {
if (resp.exists)
found = true;
});
if (!found)
{
entity.id='id1';
t.set(reservationCol.doc(entity.id), entity);
return Promise.resolve('ok');
}
else
return Promise.reject('exist');
});
});
I was facing the same problem and decided to use a combination of a batched write and "normal" reads. The decision was guided by the fact that I needed to make many reads that did not rely on each other. At first I used a method similar to the one proposed by Derrick above, but it proved not sustainable for may reads. The code dictates that every loop is blocking to the next one. What I did was to batch all the reads to run in parallel with
Promise.all
The disadvantage of this is that you dont take advantage of transaction features, but since the field I was iterested in was not changing, it made sense Here's my sample codeThis has proven to be more efficient for many reads, while remaining safe since the fields I'm interested in dont change
I couldn't figure out how to do this in pure Typescript, but I was able to find a JavaScript example that uses promises, so I adapted that to fit my needs. It seems to be working correctly, however when I run my function rapidly (by clicking on a button in rapid succession) I get console errors that read
POST https://firestore.googleapis.com/v1beta1/projects/myprojectname/databases/(default)/documents:commit 400 ()
. I am unclear on whether those are errors I should be worried about, or if they're simply a a result of the transaction retrying. I posted my own question about that, and am hopeful to get some answers on it. In the meantime, here is the code that I came up with:The Firestore doc doesn't say this, but the answer is hidden in the API reference: https://cloud.google.com/nodejs/docs/reference/firestore/0.13.x/Transaction?authuser=0#getAll
You can use
Transaction.getAll()
instead ofTransaction.get()
to get multiple documents. Your example will be: