Lesson 10 / 25
Queries and Composite Indexes
where, orderBy, limit.
Every query uses an index
Build a query with query(collectionRef, ...constraints) using where, orderBy and limit, then run it with getDocs. Firestore serves every query from an index, so query time scales with the result size rather than the collection size. Single-field indexes are created automatically; queries that combine filters and ordering on several fields need a composite index. If one is missing, the query fails with an error containing a link to create it, and you should then record it in firestore.indexes.json so deploys stay reproducible. Operators include ==, !=, <, <=, >, >=, in, not-in, array-contains and array-contains-any, with or() and and() for compound filters. Rules about combining inequalities and ordering have changed over time, so check the docs.
Fast queries over indexed data
Every Firestore query is served from an index, can be paginated with cursors and can stream live updates.
A filtered, sorted query and its index
TypeScript and firestore.indexes.json.
import { collection, query, where, orderBy, limit, getDocs } from "firebase/firestore";
const q = query(
collection(db, "posts"),
where("authorId", "==", uid),
where("published", "==", true),
orderBy("createdAt", "desc"),
limit(20),
);
const snap = await getDocs(q);
snap.forEach((d) => console.log(d.id, d.data().title));
/* firestore.indexes.json (deployed with the CLI)
{
"indexes": [{
"collectionGroup": "posts",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "authorId", "order": "ASCENDING" },
{ "fieldPath": "published", "order": "ASCENDING" },
{ "fieldPath": "createdAt", "order": "DESCENDING" }
]
}]
}
*/Count without reading everything
Aggregation queries such as getCountFromServer return counts without downloading each document; billing for aggregations differs from normal reads, so check the docs.
Quick check: A query fails with an error containing a console link. What is the most likely cause?
- A required composite index does not exist yet
- The API key is invalid
- The collection is empty
- Security Rules are disabled
Answer
A required composite index does not exist yet — Multi-field queries need composite indexes.