Create and update documents
targeted, strict document creation
On the admin SDK, we can perform strict targeted document creations, aka create a document with a controlled ID and expect a failure if the document already exists:
docRef.create(data)
The client SDK doesn't offer an equivalent function. Instead, we can do a two-step transaction where we read for document existence then write the document conditionally.
random-ID document creation (add)
The client SDK prefers random-ID creation that always succeed because the document won't already exist by design (add):
addDoc(collectionRef, data)
// db.collection("message").add(data)
upsert (set)
An upsert works regardless if a document exists or not. It is destructive, as it override any existing document.
setDoc(docRef, data)
// docRef.set(data)
update documents
We assume the document already exists: we use the update pattern or the set with merge pattern.
The update function is a strict update: it correctly fails if the document doesn't exist.
Both update and set merge expect a change object. We type the change as a Partial or as a Pick of the document:
const change: Partial<User> = { displayName: "Johnny Appleseed" }
updateDoc(docRef, change)
// docRef.update(change)
update uses the provided fields to replace the existing ones, the other fields being left unchanged.
To mutate a single field in an object field, we target it with dot notation. If we target the object instead, the omitted sub-fields are deleted (different from set with merge)
// sub-field
const change: Partial<User> = { "address.city": "Lyon" }
updateDoc(docRef, change)
If TypeScript complains about the dot notation, we use the FieldPath overload:
updateDoc(docRef, new FieldPath("address", "city"), "Lyon")
partial update with set and merge
the merge option changes the meaning of set: we are now providing a change object, not the new object.
What we target in the change object is what gets changed, including sub-fields. The omitted sub-fields are preserved (deep merge): there is no need for dot notation:
const change = { address: { city: "Lyon" } } // only changes city in address
setDoc(docRef, change, { merge: true })
// docRef.set(data, { merge: true })
relative change (increment, decrement)
We ask the server to change the field by n, which can be positive or negative. The current value is unknown:
const change = {
activityScore: increment(1), // or e.g. -1
}
// docRef.update({
// count: FieldValue.increment(1),
// })
delete field
We ask the server to delete a field. This shortcuts the need to fetch the document first and store it second omitting the given field:
updateDoc(docRef, {
fleet: deleteField(),
})
// docRef.update({
// fleet: FieldValue.delete(),
// })
server timestamp field
Ask the server to generate a Firestore timestamp value.
updateDoc(docRef, {
count: serverTimestamp(),
})
// docRef.update({
// count: FieldValue.serverTimestamp(),
// })
delete document
deleteDoc(docRef)
// docRef.delete()