Collection
Collection Reference
uses
We provide the collection reference to:
-
fetch all documents -
getDocs(colRef)
-
build a query targeting the collection -
query(colRef, filters..)
-
build an empty document reference within the collection -
doc(colRef)
-
add a document to the collection, by submitting data and delegating the id creation to the SDK -
addDoc(colRef, data)
. (it returns the reference)
We may also use it in combination with a document's ID to uniquely identify this document, such as in getDoc(colRef, id)
A documentRef already encapsulates the collection reference. As such, we don't need to provide both.
build a collection reference
The path to the collection identifies it uniquely. If the collection lives at the top, aka is not a sub-collection, the path is the same as the collection name, such as "users"
. Otherwise it's made of several components.
We indicate the collection's path, either as:
-
a single string, with no starting slash for the root collection
-
a sequence of string arguments with no slash.
const collectionRef = collection(db, "users")
const collectionRef = collection(db, `users/${uid}/custom_list`)
const collectionRef = collection(db, "users", uid, "custom_list")
// firebase-admin/firestore
const collectionRef = db.collection("users")
const collectionRef = db.collection(`users/${uid}/custom_list`)
Typescript: indicate the document's type at the collection level.
The SDK cannot infer the document type for a given collection. As such, we provide it at the collection reference level.
We may have a client specific type, one that results from a client-side transformation, that we do with a converter. In that case, we provide the client-side type first. Otherwise, we provide the same type twice.
const playersColRef = collectionRef as CollectionReference<Player, Player>
const playersColRef = collectionRef as CollectionReference<Player, FirestorePlayer>
const playersColRef = collectionRef.withConverter(myConverter)
Firestore Converter
declare transform between firestore shape and client shape.
We may want to have a shape on the client that is distinct from the one in the database. For example:
- a property is a Timestamp in the database, but we want a Date on the client.
- We want to add client only properties, such as helper properties.
In this case, we want Firebase to transform the document when
- receiving it from Firestore (
fromFirestore()
) - sending it to Firestore (
toFirestore()
)
We define a converter, made of two functions.
fromFirestore takes a query document snapshot.:
fromFirestore(snapshot: QueryDocumentSnapshot<FirestoreWorkout>): Workout{
// transform to client shape
const firestoreWorkout = snapshot.data()
const workout = { ...firestoreItem, date: firestoreItem.date.toDate()}
return workout
}
toFirestore takes the local object.
toFirestore(workout: Workout) {
// prepare the object for firestore
return { ...workout, date: Timestamp.fromDate(workout.date)}
}
and put them in a data converter of type FirestoreDataConverter, which dictates both types, provided as type parameters following the shape of: FirestoreDataConverter<AppModel, DbModel>
const myConverter: FirestoreDataConverter<Workout, FirestoreWorkout> = {
toFirestore() {},
fromFirestore() {},
}
attach the converter to the collectionRef
We attach the converter with withConverter()
const collectionRef = collection(db, "users").withConverter(myConverter)
cloud functions may not use a converter
the Admin SDK does not provide withConverter()