Query
overview
A query aims to target documents based on a set of criteria, instead of targeting documents through their reference.
the result of a query: a query snapshot
Firestore answers a query with a query snapshot. It wraps a list of document snapshots. The list stays empty if there was no match.
The document snapshots are technically of type QueryDocumentSnapshot, but this type has the same API surface than DocumentSnapshot, so they are conceptually the same.
querySnaptshot.docs // list of document snapshots
querySnaptshot.empty
Document snapshots in the array are guaranteed to have an underlying document at snapshot.data() (QueryDocumentSnapshot reflects that, removing undefined from data())
const cats = querySnapshot.docs.map((docSnapshot) => docSnapshot.data())
a collection reference is technically a query
A collection ref is accepted as a query. In that case, we receive all documents:
getDocs(collectionRef)
collectionRef.get()
build a query
build a query
We query documents that match some criteria. We request a specific order and limit the document count.
const q = query(collectionRef, where(..), where(..), orderBy(..), limit(..))
const q = collection(..).where(..).orderBy(..).limit(..)
where and where operators
We filter documents based on a property. We may request an exact value, or one within a range.
Note: documents that do not possess the property are filtered out.
where(propertyName, operator, value)
where("id", "==", user.id)
where operators (strings):
<
<=
>
>=
==
!=
array-contains // the array contains the specified value
array-contains-any // the array contains at least one of A, B or C ..
in // the property is equal to either A, B or C
not-in // the property is different from A, B and C.
order documents based on a field
We order documents based on the value of a given field. By default, it sorts documents so that the value is ascending. It's best to be explicit about the ordering rather than rely on the default one.
orderBy(propertyName, orderDirection)
orderBy("postCount", "asc")
orderBy("postCount", "desc")
orderBy("postCount") // ascending
we can start from a given value, for example, documents that have at least 10 posts, or more than 10 posts:
startAt(10)
startAfter(10)
limit the size of the query
get at most n documents
limit(n)
limit(5)
pagination: start at or after a given document, that acts as a cursor
When doing pagination, we store the document snapshot we received last, and provide it in the new query.
startAfter(docSnapshot) // start after the docSnapshot
startAt(docSnapshot) // start at the docSnapshot (include it again)
run the query
The client SDK's function name (getDocs) hints that we may receive several documents. The admin SDK is a get function from the query object.
getDocs(query)
query.get()
real-time listener over the query
we provide a callback to handle the query snapshot.
const unsub = onSnapshot(query, (qs) => {
const documents = qs.docs.map((docSnapshot) => docSnapshot.data())
setMessages(documents)
})