Paginate data with query cursors

With query cursors in Firestore, you can split data returned by a query into batches according to the parameters you define in your query.

Query cursors define the start and end points for a query, allowing you to:

  • Return a subset of the data.
  • Paginate query results.

However, to define a specific range for a query, you should use the where() method described in Simple Queries.

Add a simple cursor to a query

Use the startAt() or startAfter() methods to define the start point for a query. The startAt() method includes the start point, while the startAfter() method excludes it.

For example, if you use startAt(A) in a query, it returns the entire alphabet. If you use startAfter(A) instead, it returns B-Z.

Web version 9

import { query, orderBy, startAt } from "firebase/firestore";  

const q = query(citiesRef, orderBy("population"), startAt(1000000));

Web version 8

citiesRef.orderBy("population").startAt(1000000);
Swift
Note: This product is not available on watchOS and App Clip targets.
// Get all cities with population over one million, ordered by population.
db.collection("cities")
  .order(by: "population")
  .start(at: [1000000])
Objective-C
Note: This product is not available on watchOS and App Clip targets.
// Get all cities with population over one million, ordered by population.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryStartingAtValues:@[ @1000000 ]];
Kotlin
Android
// Get all cities with a population >= 1,000,000, ordered by population,
db.collection("cities")
    .orderBy("population")
    .startAt(1000000)
Java
Android
// Get all cities with a population >= 1,000,000, ordered by population,
db.collection("cities")
        .orderBy("population")
        .startAt(1000000);

Dart

db.collection("cities").orderBy("population").startAt([1000000]);
Java
Query query = cities.orderBy("population").startAt(4921000L);
Python
cities_ref = db.collection("cities")
query_start_at = cities_ref.order_by("population").start_at({"population": 1000000})
Python
(Async)
cities_ref = db.collection("cities")
query_start_at = cities_ref.order_by("population").start_at({"population": 1000000})
C++
// Get all cities with a population >= 1,000,000, ordered by population,
db->Collection("cities")
    .OrderBy("population")
    .StartAt({FieldValue::Integer(1000000)});
Node.js
const startAtRes = await db.collection('cities')
  .orderBy('population')
  .startAt(1000000)
  .get();
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).StartAt(1000000)
PHP

PHP

To authenticate to Firestore, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

$query = $citiesRef
    ->orderBy('population')
    ->startAt([1000000]);
Unity
Query query = citiesRef.OrderBy("Population").StartAt(1000000);
C#
Query query = citiesRef.OrderBy("Population").StartAt(1000000);
Ruby
query = cities_ref.order("population").start_at(1_000_000)

Similarly, use the endAt() or endBefore() methods to define an end point for your query results.

Web version 9

import { query, orderBy, endAt } from "firebase/firestore";  

const q = query(citiesRef, orderBy("population"), endAt(1000000));

Web version 8

citiesRef.orderBy("population").endAt(1000000);
Swift
Note: This product is not available on watchOS and App Clip targets.
// Get all cities with population less than one million, ordered by population.
db.collection("cities")
  .order(by: "population")
  .end(at: [1000000])
Objective-C
Note: This product is not available on watchOS and App Clip targets.
// Get all cities with population less than one million, ordered by population.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryEndingAtValues:@[ @1000000 ]];
Kotlin
Android
// Get all cities with a population <= 1,000,000, ordered by population,
db.collection("cities")
    .orderBy("population")
    .endAt(1000000)
Java
Android
// Get all cities with a population <= 1,000,000, ordered by population,
db.collection("cities")
        .orderBy("population")
        .endAt(1000000);

Dart

db.collection("cities").orderBy("population").endAt([1000000]);
Java
Query query = cities.orderBy("population").endAt(4921000L);
Python
cities_ref = db.collection("cities")
query_end_at = cities_ref.order_by("population").end_at({"population": 1000000})
Python
(Async)
cities_ref = db.collection("cities")
query_end_at = cities_ref.order_by("population").end_at({"population": 1000000})
C++
// Get all cities with a population <= 1,000,000, ordered by population,
db->Collection("cities")
    .OrderBy("population")
    .EndAt({FieldValue::Integer(1000000)});
Node.js
const endAtRes = await db.collection('cities')
  .orderBy('population')
  .endAt(1000000)
  .get();
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).EndAt(1000000)
PHP

PHP

To authenticate to Firestore, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

$query = $citiesRef
    ->orderBy('population')
    ->endAt([1000000]);
Unity
Query query = citiesRef.OrderBy("Population").EndAt(1000000);
C#
Query query = citiesRef.OrderBy("Population").EndAt(1000000);
Ruby
query = cities_ref.order("population").end_at(1_000_000)

Use a document snapshot to define the query cursor

You can also pass a document snapshot to the cursor clause as the start or end point of the query cursor. The values in the document snapshot serve as the values in the query cursor.

For example, take a snapshot of a "San Francisco" document in your data set of cities and populations. Then, use that document snapshot as the start point for your population query cursor. Your query will return all the cities with a population larger than or equal to San Francisco's, as defined in the document snapshot.

Web version 9

import { collection, doc, getDoc, query, orderBy, startAt } from "firebase/firestore";  
const citiesRef = collection(db, "cities");

const docSnap = await getDoc(doc(citiesRef, "SF"));

// Get all cities with a population bigger than San Francisco
const biggerThanSf = query(citiesRef, orderBy("population"), startAt(docSnap));
// ...