Search code examples
typescriptfirebasegoogle-cloud-firestoretransactions

Firebase: Use converter in transaction with Firestore


I am trying to use a Firestore data converter inside a transaction where I am adding a record to a collection (entries) and updating a counter in another collection (users). However, I cannot figure out how to use the converter inside a transaction, and have been unable to find any examples. While the Firebase docs are typically excellent, they seem to fall a bit short with regards to transactions.

// Add new entry and increment user entry counter
async addEntry(entry: Entry): Promise<void> {
    const entryRef = db.collection("entries").doc(entry.id);
    const userRef = db.collection("user").doc(entry.userId);

    await db.runTransaction(async (transaction) => {
      // NOTE: Cannot use converter with transaction???
      await transaction.set(entryRef, entry).withConverter(entryConverter);

      // QUESTION: Is this a proper use of "increment" (ie. inside a transaction)?
      await transaction.update(userRef, { entries: FieldValue.increment(1) });
    });
}

This is what it would look like without the transaction and using a converter (but I need the transaction).

await db.collection("entries")
  .doc(entry.id)
  .withConverter(entryConverter)
  .set(entry);
await db.collection("users")
  .doc(entry.userId)
  .update({ entries: FieldValue.increment(1) });

How can I safely perform these two operations in a transaction while using a converter for the new data?


Solution

  • Indeed this is not documented, but you can set the converter outside the transaction and before specifying a document, since the converter is being applied to the collection, and it should work. So something like:

    async addEntry(entry: Entry): Promise<void> {
        const entryRef = db.collection("entries").withConverter(entryConverter).doc(entry.id);
        const userRef = db.collection("user").doc(entry.userId);
    
        await db.runTransaction(async (transaction) => {
          await transaction.set(entryRef, entry);
          await transaction.update(userRef, { entries: FieldValue.increment(1) });
        });
    }