Firestore Queries Deep Dive: Filters, Sorting, Pagination & Indexes
In this tutorial, you will learn about Firestore Queries Deep Dive: Filters, Sorting, Pagination & Indexes. We cover key concepts, practical examples, and best practices to help you master this topic.
Firestore queries use indexes to filter, sort, and paginate documents with compound where clauses, orderBy, limit, cursors, and collection group queries for efficient data retrieval.
What You'll Learn
How to build efficient Firestore queries with multiple filters, sort results, paginate with cursors, query across subcollections, and create Composite indexes for query performance.
Why It Matters
Poor queries cost money and slow down your app. Each document read is billed, and unindexed queries fail at scale. DodaTech's threat dashboard queries 50K+ scan records daily with sub-second response times using well-designed indexes.
Real-World Use
A security operations dashboard: filter scans by date range and severity, sort by threat count, paginate results 25 at a time, and query across all devices for enterprise-wide reports.
flowchart LR
A["Query Request\nFilter + Sort"] --> B{"Has Index?"}
B -->|Yes| C["Return Results\nSub-second"]
B -->|No| D["Error: needs\ncomposite index"]
D --> E["Create Index\nConsole / CLI"]
E --> C
style C fill:#bbf7d0,stroke:#16a34a
style D fill:#fecaca,stroke:#dc2626
Basic Filtering
import { collection, query, where, getDocs } from "firebase/firestore";
// Single condition filter
async function getHighThreatScans() {
const q = query(
collection(db, "scans"),
where("severity", "==", "high")
);
const snapshot = await getDocs(q);
snapshot.forEach(doc => console.log(doc.id, doc.data()));
}
// Expected output: scan_001 { severity: "high", deviceId: "dev_abc", ... }
// scan_002 { severity: "high", deviceId: "dev_def", ... }
Compound Queries
import { query, where, orderBy, limit } from "firebase/firestore";
// Multiple conditions with ordering
async function getRecentCriticalScans() {
const q = query(
collection(db, "scans"),
where("severity", "==", "critical"),
orderBy("timestamp", "desc"),
limit(10)
);
const snapshot = await getDocs(q);
console.log("Recent critical scans:", snapshot.size);
}
// Expected output: Recent critical scans: 10
Pagination with Cursors
import { query, orderBy, limit, startAfter, getDocs } from "firebase/firestore";
async function paginateScans(lastDoc) {
const q = query(
collection(db, "scans"),
orderBy("timestamp", "desc"),
startAfter(lastDoc),
limit(25)
);
const snapshot = await getDocs(q);
const lastVisible = snapshot.docs[snapshot.docs.length - 1];
console.log("Page size:", snapshot.size, "Next cursor:", lastVisible?.id);
}
// Expected output: Page size: 25 Next cursor: scan_026
Collection Group Queries
import { collectionGroup, query, where } from "firebase/firestore";
// Query across all subcollections named "scans"
async function getAllScansForUser(userId) {
const q = query(
collectionGroup(db, "scans"),
where("userId", "==", userId)
);
const snapshot = await getDocs(q);
console.log("Total scans across all devices:", snapshot.size);
}
// Expected output: Total scans across all devices: 47
Creating Composite Indexes
// When you run a compound query without an index, Firestore throws an error
// with a direct link to create the required index.
async function queryNeedingIndex() {
const q = query(
collection(db, "scans"),
where("severity", "==", "high"),
where("deviceOs", "==", "Windows"),
orderBy("timestamp", "desc")
);
try {
await getDocs(q);
} catch (err) {
console.log("Index needed:", err.message);
// Error includes link to Firebase Console to create index
}
}
// Expected output: Index needed: The query requires an index. You can create it here: https://console.firebase.google.com/...
Common Mistakes
1. Querying Without an Index
Firestore requires indexes for compound queries. The error message includes a direct link to create the needed index — use it immediately.
2. Using Range Filters on Multiple Fields
Firestore only supports range conditions (<, <=, >, >=, !=) on one field per query. Combine range with equality on other fields using composite indexes.
3. Forgetting orderBy Direction in Index
Composite indexes must include the sort direction (asc/desc) matching your orderBy. Mismatched directions cause query failures.
4. Pagination Without Cursors
Using offset instead of cursors is expensive — Firestore reads every skipped document. Use startAfter or startAt with a document snapshot.
5. Not Using select() to Reduce Read Costs
// Fetch only specific fields to reduce read costs
import { select } from "firebase/firestore";
const q = query(
collection(db, "scans"),
select("severity", "timestamp", "deviceId")
);
Practice Questions
- What is a composite index and when do you need one?
- How does cursor-based pagination differ from offset pagination?
- What is a collection group query and when would you use it?
- Why can Firestore only support range filters on one field?
Answers:
- A composite index indexes multiple fields together, required for compound queries with equality + range or multiple equality filters.
- Cursor pagination (
startAfter,startAt) reads only the requested page. Offset reads all skipped documents, costing more reads. - Collection group queries search across all subcollections with the same name, useful for querying data across a hierarchy.
- Firestore's index structure stores data ordered by the first indexed field, then the second. Multiple range fields would require complex multi-dimensional indexing.
Challenge: Build a paginated threat-feed endpoint that filters by severity (equality), sorts by timestamp (descending, limit 20), uses cursor pagination, and creates the composite index through the Firebase Console.
FAQ
Mini Project
Create an advanced query layer for Durga Antivirus Pro: filter scans by severity + date range, sort by threat count descending, paginate with cursors (25 per page), query across all devices with collection group, and create the required composite indexes.
What's Next
Firestore Security Rules — secure your Firestore data with access control rules.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro