Upserting or Updating in Firestore? Choosing Between Set with {merge: true} and Update
- Behavior: This operation acts like an "upsert," meaning it either updates an existing document or creates a new one if it doesn't exist.
- Data Handling: It provides a complete picture of the document's data. Any fields not included in the
set
call will be set to null or their default values. - Use Cases: Ideal for scenarios where you want to ensure all fields are defined and have a known state, even if they're not explicitly provided in the update.
Firestore Update
- Behavior: This operation specifically updates existing documents. It targets only the fields you provide in the update data.
- Data Handling: Only the specified fields are modified. Existing fields not included in the update remain unchanged.
- Use Cases: Well-suited for partial updates where you only need to modify specific aspects of a document without affecting other fields.
Key Differences:
Feature | Firestore Set with {merge: true} | Firestore Update |
---|---|---|
Document Creation | Creates a new document if it doesn't exist | Requires the document to already exist (fails otherwise) |
Data Handling | Sets all fields provided, others become null/default | Updates only specified fields, leaves others unchanged |
Use Case | Upsert-like operations (ensure all fields defined) | Partial updates (modify specific fields) |
Choosing the Right Method:
- If you need to create a document if it's missing or want to define the entire document state, use
set
with{merge: true}
. - If you only want to update specific fields in an existing document, use
update
.
Additional Considerations:
- Both methods can handle nested fields using dot notation (e.g.,
data.user.name
). update
can also be used for server-side timestamp updates usingFieldValue.serverTimestamp()
.
import { getFirestore, collection, doc, set } from "firebase/firestore";
const db = getFirestore(); // Replace with your Firestore instance
// Create a reference to a document (creates if it doesn't exist)
const docRef = collection(db, "users").doc("user1");
const data = {
name: "John Doe",
// Omit other fields (will be set to null or default values)
};
set(docRef, data, { merge: true })
.then(() => {
console.log("Document upserted successfully!");
})
.catch((error) => {
console.error("Error upserting document:", error);
});
import { getFirestore, collection, doc, update } from "firebase/firestore";
const db = getFirestore(); // Replace with your Firestore instance
// Reference to an existing document
const docRef = collection(db, "users").doc("user1");
const updateData = {
age: 30, // Update only specific field
};
update(docRef, updateData)
.then(() => {
console.log("Document updated successfully!");
})
.catch((error) => {
console.error("Error updating document:", error);
});
Explanation:
- Imports: Both examples import necessary functions from
firebase/firestore
. - Firestore Instance: Replace
getFirestore()
with your Firestore instance. - Document Reference:
set
with{merge: true}
: Creates a reference to a document even if it doesn't exist yet.update
: Requires the document to already exist.
- Data:
set
with{merge: true}
: Provides a complete data object, even with missing fields.update
: Targets only the fields included in theupdateData
object.
- Firestore Call:
set
with{merge: true}
: Usesset
with the{merge: true}
option.update
: Usesupdate
to modify specific fields.
- Error Handling: Both examples handle potential errors during the Firestore operation.
Instead of manually setting timestamps in your code, you can leverage Firestore's server-side timestamps. This ensures consistent and accurate timestamps across different clients.
JavaScript (using FieldValue.serverTimestamp()
):
import { getFirestore, collection, doc, update, FieldValue } from "firebase/firestore";
const updateData = {
updatedAt: FieldValue.serverTimestamp(), // Use server timestamp
};
// ... rest of your update code
Transactions:
For complex updates involving multiple documents, consider using transactions to ensure data consistency across those documents. Transactions are atomic operations, meaning either all updates succeed or none of them do.
Refer to the official Firebase documentation for details on transactions:
Batch Writes:
For efficient bulk updates of multiple documents, batch writes can be a good option. They group multiple write operations (sets, updates, or deletes) and submit them as a single request to Firestore.
Conditional Updates:
Firestore allows for conditional updates where you can modify data based on a specific condition existing in the document. This helps prevent overwriting unexpected data changes.
Refer to the official Firebase documentation for details on conditional updates:
The best method depends on your specific use case. Here's a quick guide:
- Simple updates: Use
update
for partial updates in existing documents. - Upsert-like behavior: Use
set
with{merge: true}
for creating or updating documents while ensuring all fields are defined. - Server-side timestamps: Leverage
FieldValue.serverTimestamp()
for consistent timestamps. - Complex multi-document updates: Consider using transactions for data consistency.
- Bulk updates: Use batch writes for efficiency when updating multiple documents.
- Conditional updates: Employ conditional updates to modify data based on existing conditions.
database firebase google-cloud-firestore