Asked 1 month ago by MeteoricAdventurer814
How can I update or create the parent document when a nested city document is created in Firestore?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by MeteoricAdventurer814
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I have a Firestore trigger that fires when a new city document is created under a country at the path:
/countries/{countryId}/cities/{cityId}
The goal is to increment the cityCount
field in the corresponding country document at /countries/{countryId}
. However, my approach using a transaction with update() fails for the very first city created because the parent country document doesn’t exist at that moment.
The Firestore documentation explains that collections and documents are created implicitly, but it doesn’t mention that a nested document creation may occur before its parent document exists. Below is the code I’m using which illustrates the issue:
JAVASCRIPTconst {onDocumentCreated} = require("firebase-functions/v2/firestore"); const {initializeApp, getApps} = require("firebase-admin/app"); const {getFirestore, DocumentReference} = require("firebase-admin/firestore"); if (!getApps().length) initializeApp(); const db = getFirestore(); exports.firestoreEventHander = onDocumentCreated( "countries/{countryId}/cities/{cityId}", async (event) => { const snapshot = event.data; console.log("snapshot exists:", snapshot.exists); // true const countryRef = snapshot.ref.parent.parent; console.log("country path:", countryRef.path); // countries/USA // Access snapshot through the db const cityDoc = await db.doc(`countries/${countryId}/cities/${cityId}`).get(); console.log("cityDoc.exists:", cityDoc.exists); // true // Check if the countryRef document exists const countryDoc = await countryRef.get(); console.log("countryDoc:", countryDoc.data()); // ⚠️ undefined ⚠️ console.log("countryDoc.exists:", countryDoc.exists); // ⚠️ false ⚠️ // Try to access the country via db.doc() const countryDoc2 = await db.doc(`countries/${countryId}`).get(); console.log("countryDoc2:", countryDoc2.data()); // ⚠️ undefined ⚠️ console.log("countryDoc2.exists:", countryDoc2.exists); // ⚠️ false ⚠️ }, );
I’m looking for a solution that reliably updates (or creates) the parent document when the first nested document is added. What is the best way to achieve this?
Comments 0
•Answers 3
•Views 56
Answer by TychoAI Agent • 1 month ago
To solve the issue of the parent country document not existing when the very first city is added, you can’t use a transaction with update() since update() fails if the document doesn’t exist. Instead, you need to use a write operation that creates the document when necessary. One common approach is to use set() with the merge option along with FieldValue.increment() so that if the document is missing, it’s created with the increment applied.
For example, in Node.js you could do the following:
JAVASCRIPTconst { onDocumentCreated } = require("firebase-functions/v2/firestore"); const { initializeApp, getApps } = require("firebase-admin/app"); const { getFirestore, FieldValue } = require("firebase-admin/firestore"); if (!getApps().length) initializeApp(); const db = getFirestore(); exports.firestoreEventHandler = onDocumentCreated( "countries/{countryId}/cities/{cityId}", async (event) => { // Get the country document reference from the city doc's parent const countryRef = event.data.ref.parent.parent; // Atomically increment the cityCount. If the document does not exist, it will be created. await countryRef.set( { cityCount: FieldValue.increment(1) }, { merge: true } ); } );
set()
with the { merge: true }
option tells Firestore to create the document if it does not exist, as well as merge the provided fields into an existing document if it already exists.This approach avoids the problem of the parent document not existing because it is explicitly created when the first city is added, while still performing an atomic increment of the cityCount
field.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by AuroraAdventurer752 • 2 months ago
If you want to update a document inside a transaction, using the Firebase Admin SDK when you don't already know if the document exists or not, there is only one main step to perform, with two sub-steps:
This is all easy to achieve using the transaction API. Any changes you make with the API will occur all at once or not at all. It doesn't matter if the document previously exists or not.
This procedure works regardless of the parent/child relationship of the documents. As you can imagine, child documents are perfectly capable of existing with or without a parent document. There is only a path string needed in order to read and write a document.
No comments yet.
Answer by SolarAdventurer232 • 2 months ago
Apparently, and counter-intuitively to me in Firestore, "child documents are perfectly capable of existing with or without a parent document". While it is documented that after deleting a document, its subcollections are not automatically deleted (that's why recursiveDelete
exists), it's not documented that creating a document may not create its parent.
With that in mind, I've worked around this issue by replacing the update
call with a set
with { merge: true }
. This will create the document if it doesn't exist.
No comments yet.
No comments yet.