The operation of fetching multiple documents within a transaction loop is not functioning as anticipated

I am encountering an issue where I am attempting to retrieve multiple documents within a transaction and then update them all in the same transaction (due to their interdependence). Despite following the rule of ensuring all reads occur before any writes, I keep receiving the error message

The referenced transaction has expired or is no longer valid
in my console.

Although I can see the transaction ids being logged with

console.log(Transaction id: ${transactionId})
, I never see any output from
console.log(Transaction ${transactionId} fetched and pushed to array)
.

What could be causing my transaction to fail?

try {
        return admin.firestore().runTransaction(async t => {
            const bundleRef = admin.firestore().doc(`bundles/${bundleId}`)
            const bundle = await t.get(bundleRef)
            const bundleData = bundle.data()
  
            const transactions:FirebaseFirestore.DocumentSnapshot[] = []

            await bundleData!.transactionIds.forEach(async (transactionId: string) => {
                console.log(`Transaction id: ${transactionId}`)
                const transactionRef = admin.firestore().doc(`transactions/${transactionId}`)
                const transaction = await t.get(transactionRef)
                transactions.push(transaction)
                console.log(`Transaction ${transactionId} fetched and pushed to array`)
            })

            console.log(`All transactions fetched`)
            transactions.forEach(async transaction => {
                console.log(`Updating transaction ${transaction.id}`)
                const transactionData = transaction.data()
                transactionData!.timestamp = admin.firestore.FieldValue.serverTimestamp()
                t.update(transaction.ref, transactionData!)
                console.log(`Transaction ${transaction.id} updated`)
            })
            console.log(`Update bundle ${bundle.id}`)
            bundleData!.timestamp = admin.firestore.FieldValue.serverTimestamp()
            t.update(bundle.ref, bundleData!)
            console.log(`Finished`)
        })
    } catch (err) {
        return Promise.reject(new Error("Transaction failed."));
    }

Answer №1

According to Doug's explanation in the comment, using forEach() and async/await in this manner is not recommended. To retrieve all transaction documents, it is best to utilize the getAll() method as shown below:

    try {

        return admin.firestore().runTransaction(async t => {

            const bundleRef = admin.firestore().doc(`bundles/${bundleId}`)
            const bundle = await t.get(bundleRef)
            const bundleData = bundle.data()

            const transactionRefs = []

            bundleData.transactionIds.forEach((transactionId) => {
                const transactionRef = admin.firestore().doc(`transactions/${transactionId}`)
                transactionRefs.push(transactionRef);
            })

            const transactionSnapshots = await t.getAll(...transactionRefs);

            transactionSnapshots.forEach(transactionSnap => {
                t = t.update(transactionSnap.ref, { timestamp: admin.firestore.FieldValue.serverTimestamp() });
            })

            t.update(bundle.ref, { timestamp: admin.firestore.FieldValue.serverTimestamp() })
            console.log(`Finished`)
        })
    } catch (err) {
        console.log(err)
        return null;
    }

Important notes:

  • Avoid using
    transactionData!.timestamp = admin.firestore.FieldValue.serverTimestamp()
    as it results in overwriting existing data with the same values. Simply update with the timestamp, which is the only changing field.
  • (Object types have been omitted in this code snippet, tailored for a JavaScript-configured project on the current machine).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Kubernetes Cluster Encountering Error with Google FCM Firebase-Admin initializeApp() Function

Currently, I am in the process of setting up a NodeJs server and integrating FCM for push notifications. While everything runs smoothly locally, I encounter an error when running on my K8S cluster. An issue arises with FirebaseAppError: The credential impl ...

Encountering a deployment issue with Next.js on AWS Amplify

One day, while hosting my Next.js web app with SSR on AWS Amplify, I encountered a frustrating error 503. https://i.sstatic.net/59vk5.png Delving into the AWS console, I stumbled upon a CloudWatch log detailing an error in the lambda function responsible ...

Validating a single field name with various DTO types based on conditions in a NestJS application

There is a field named postData in EmailTypeDto, but it has different types based on conditions. It may be confusing to explain in words, but the code makes it clear. export class EmailTypeDto { @IsEnum(EmailType) public type: EmailType; @ValidateIf ...

"Encountering connectivity issues between NestJs and TypeORM when trying to establish a

My current challenge involves connecting to MySQL. I have set the database connection variables in a .env file located in the root directory, and I am initializing the connection in the app.module.ts file. The problem arises when I attempt to create or run ...

Insert a new item into the array located within an Observable entity

In my angular application, I have a page where I am showcasing an object that contains an array of comments within it. This object is loaded into my class as an Observable and then displayed in the HTML using: <div class="container-fluid mt--7" ...

The function successfully triggers when clicked using (React, JS, TS) but does not respond to key presses

When the function is called with "onClick", it works correctly, but when called with "onKeyPress", it does not execute an if statement. scenario Consider a scenario where you can search for food recipes (e.g. "pizza") and receive a list of recipes from a ...

What is causing the difficulty in accessing the 'query' feature within the API, and why is the question bank failing to display?

Just wanted to mention that I am still learning about class based components, setState, and other concepts in async JS like axios. Below is a very basic example of what I can currently do. This is App.js: import Questions from './components/Ques ...

Exploring Functions in Object Literal Notation in TypeScript: Why is the Context of 'this' Assigned as Type 'any'?

It appears that the question has been posed before, but my search yielded no results. The issue at hand seems rather straightforward. TypeScript integrates well with object literal notation, however, when methods are defined within, it struggles to handle ...

What is the procedure for obtaining FlowNode in the typescript ast api?

Trying to access and resolve foo and bar from the nodes variable. Upon examination in ts-ast-viewer, it is evident that TypeScript recognizes foo and bar within the nodes node under the FlowNode section (node -> initializer -> elements -> escaped ...

Angular version 12 (node:3224) UnhandledPromiseRejectionWarning: Issue encountered with mapping:

Trying to generate the translation file in my Angular project using the command ng extract-i18n --output-path src/translate, I encountered this error message: \ Generating browser application bundles (phase: building)...(node:3224) UnhandledPromiseRej ...

Is there a specific instance where it would be more appropriate to utilize the styled API for styling as opposed to the sx prop in Material-

I am currently in the process of migrating an existing codebase to Material UI and am working towards establishing a styling standard for our components moving forward. In a previous project, all components were styled using the sx prop without encounteri ...

Is it possible to utilize a TypeScript type in conjunction with io-ts?

Currently, I am in the process of validating API responses with io-ts. In my TypeScript setup, I have already defined the following data structure: export type Group = { id: number; name: string; } Now, my objective is to incorporate this type into ...

The correct way to add to a string array that has been passed as props to a functional component

There is a parent component that establishes a useState hook with a string array. Then, there is a child component tasked with updating the string array. To accomplish this, both the string array and the useState function are passed to the child component. ...

Activate the Keypress event to update the input value in React upon pressing the Enter

I am facing an issue where I need to reset the value of an input using a method triggered by onPressEnter. Here is the input code: <Input type="text" placeholder="new account" onPressEnter={(event) => this.onCreateAccount(event)}> < ...

Executing Firebase Cloud Functions to perform write operations within a database event function

Exploring the world of Firebase functions has been an exciting learning journey for me. This innovative feature is proving to be incredibly powerful and beneficial. I'm eager to utilize a function that can capture a database writing event, perform a ...

There is no overload that matches this call in Next.js/Typescript

I encountered a type error stating that no overload matches this call. Overload 1 of 3, '(props: PolymorphicComponentProps<"web", FastOmit<Omit<AnchorHTMLAttributes, keyof InternalLinkProps> & InternalLinkProps & { ...; ...

What is the method for extending props from React.HTMLProps<HTMLButtonElement>?

"react": "^17.0.2", "typescript": "^4.2.4" Can someone help me understand how to extend props from React.HTMLProps? import { FC, HTMLProps } from 'react' export interface SliderButtonProps extends HTMLPro ...

Managing data with Angular 2: Setting and retrieving values

In my current project, I am working on developing a service that can parse data to different components based on various routes. When I call this service within the same component, everything works as expected and I get the desired results. However, when ...

VSCode still throwing a replaceAll warning, despite targeting ES2021

Here is the tsconfig file for my Vue project: { "extends": "@vue/tsconfig/tsconfig.web.json", "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.json"], "exclude ...

The setupFile defined in Jest's setupFilesAfterEnv configuration is not recognized by the VSCode IDE unless the editor is actively open

I've put together a simplified repository where you can find the issue replicated. Feel free to give it a try: https://github.com/Danielvandervelden/jest-error-minimal-repro Disclaimer: I have only tested this in VSCode. I'm encountering diffic ...