Let's say I'm adding some data to Cloud Firestore:
import { collection, addDoc, serverTimestamp } from 'firebase/firestore';
const ref = await addDoc(collection(db, 'posts'), {
createdAt: serverTimestamp(),
modifiedAt: null,
title: 'A Title',
});
I have rules enforcing createdAt
should equal request.time
and never be updated, modifiedAt
should be null
on create but equal to request.time
on update, and title
should be a string.
The problem arises when I try to update this document:
import { doc, updateDoc } from 'firebase/firestore';
await updateDoc(ref, {
createdAt: ???, // what goes here?
modifiedAt: serverTimestamp(),
title: 'A Title',
});
I need createdAt
to be that initial server timestamp value (as a Date
object). I can't just put serverTimestamp()
because Firestore will try to update that field to the new request.time
value and rule enforcement will fail. I can't do a partial update (by omitting createdAt
) because I'm using a client-side ORM (Ember Data), which isn't capable of handling partial updates like this.
Is there a way to retrieve whatever that initial serverTimestamp
value became after calling addDoc
, without making a second request immediately after addDoc
to retrieve the document we just created? It seems unnecessary to make that second request, since I already have all the data (sans the timestamp values). I'm basically just trying to avoid adding a second request app-wide every time a new record is created.
CodePudding user response:
An updateDoc
operation (unlike an addDoc
operation or the default setDoc
operation) will only overwrite the keys that you actually specify. So to leave createdAt
as-is, simply omit it.
await updateDoc(ref, {
modifiedAt: serverTimestamp(),
title: 'A Title',
});
To pluck the key from your CRM, use delete
on the key.
const dataToUpdate = {
createdAt: "somevalue",
modifiedAt: serverTimestamp(),
title: 'A Title'
}
delete dateToUpdate.createdAt;
await updateDoc(ref, dataToUpdate);
Additionally, adding a getDoc
immediately after isn't as network expensive as you think it is. If your application uses that document anywhere in your application (either listening to the document itself or its parent collection), your client app will be notified and given the updated data to store in its local cache regardless of if you need it immediately after adding it.
const ref = await addDoc(collection(db, 'posts'), {
createdAt: serverTimestamp(),
modifiedAt: null,
title: 'A Title',
});
const snapshotWithServerTimestamps = await getDoc(ref);