# Queries and Composite Indexes — Firebase

Source: https://www.skillbyai.com/en/firebase/qu-query

> 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.

![Three ideas: queries and indexes, cursor pagination, realtime and offline.](assets/figures/firebase/section-4-map.svg) — Figure 4.1 — Queries, indexes, cursors and listeners.

## A filtered, sorted query and its index

TypeScript and firestore.indexes.json.

```typescript
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.

**Quiz:** A query fails with an error containing a console link. What is the most likely cause?

- [x] 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.
