Paginate data with query cursors
Stay organized with collections
Save and categorize content based on your preferences.
With query cursors in Cloud 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
import{query,orderBy,startAt}from"firebase/firestore"; constq=query(citiesRef,orderBy("population"),startAt(1000000));
Web
citiesRef.orderBy("population").startAt(1000000);
Swift
// Get all cities with population over one million, ordered by population. db.collection("cities") .order(by:"population") .start(at:[1000000])
Objective-C
// Get all cities with population over one million, ordered by population. [[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"population"] queryStartingAtValues:@[@1000000]];
Kotlin
// Get all cities with a population >= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .startAt(1000000)
Java
// 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
Queryquery=cities.orderBy("population").startAt(4921000L);Python
cities_ref = db.collection("cities")
query_start_at = cities_ref.order_by("population").start_at({"population": 1000000})Python
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
conststartAtRes=awaitdb.collection('cities')
.orderBy('population')
.startAt(1000000)
.get();Go
query:=client.Collection("cities").OrderBy("population",firestore.Asc).StartAt(1000000)PHP
PHP
For more on installing and creating a Cloud Firestore client, refer to Cloud Firestore Client Libraries.
$query = $citiesRef
->orderBy('population')
->startAt([1000000]);Unity
Queryquery=citiesRef.OrderBy("Population").StartAt(1000000);
C#
Queryquery=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
import{query,orderBy,endAt}from"firebase/firestore"; constq=query(citiesRef,orderBy("population"),endAt(1000000));
Web
citiesRef.orderBy("population").endAt(1000000);
Swift
// Get all cities with population less than one million, ordered by population. db.collection("cities") .order(by:"population") .end(at:[1000000])
Objective-C
// Get all cities with population less than one million, ordered by population. [[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"population"] queryEndingAtValues:@[@1000000]];
Kotlin
// Get all cities with a population <= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .endAt(1000000)
Java
// 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
Queryquery=cities.orderBy("population").endAt(4921000L);Python
cities_ref = db.collection("cities")
query_end_at = cities_ref.order_by("population").end_at({"population": 1000000})Python
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
constendAtRes=awaitdb.collection('cities')
.orderBy('population')
.endAt(1000000)
.get();Go
query:=client.Collection("cities").OrderBy("population",firestore.Asc).EndAt(1000000)PHP
PHP
For more on installing and creating a Cloud Firestore client, refer to Cloud Firestore Client Libraries.
$query = $citiesRef
->orderBy('population')
->endAt([1000000]);Unity
Queryquery=citiesRef.OrderBy("Population").EndAt(1000000);
C#
Queryquery=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
import{collection,doc,getDoc,query,orderBy,startAt}from"firebase/firestore"; constcitiesRef=collection(db,"cities"); constdocSnap=awaitgetDoc(doc(citiesRef,"SF")); // Get all cities with a population bigger than San Francisco constbiggerThanSf=query(citiesRef,orderBy("population"),startAt(docSnap)); // ...
Web
varcitiesRef=db.collection("cities"); returncitiesRef.doc("SF").get().then((doc)=>{ // Get all cities with a population bigger than San Francisco varbiggerThanSf=citiesRef .orderBy("population") .startAt(doc); // ... });
Swift
db.collection("cities") .document("SF") .addSnapshotListener{(document,error)in guardletdocument=documentelse{ print("Error retreving cities: \(error.debugDescription)") return } // Get all cities with a population greater than or equal to San Francisco. letsfSizeOrBigger=db.collection("cities") .order(by:"population") .start(atDocument:document) }
Objective-C
[[[dbcollectionWithPath:@"cities"]documentWithPath:@"SF"] addSnapshotListener:^(FIRDocumentSnapshot*snapshot,NSError*error){ if(snapshot==nil){ NSLog(@"Error retreiving cities: %@",error); return; } // Get all cities with a population greater than or equal to San Francisco. FIRQuery*sfSizeOrBigger=[[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"population"] queryStartingAtDocument:snapshot]; }];
Kotlin
// Get the data for "San Francisco" db.collection("cities").document("SF") .get() .addOnSuccessListener{documentSnapshot-> // Get all cities with a population bigger than San Francisco. valbiggerThanSf=db.collection("cities") .orderBy("population") .startAt(documentSnapshot) // ... }
Java
// Get the data for "San Francisco" db.collection("cities").document("SF") .get() .addOnSuccessListener(newOnSuccessListener<DocumentSnapshot>(){ @Override publicvoidonSuccess(DocumentSnapshotdocumentSnapshot){ // Get all cities with a population bigger than San Francisco. QuerybiggerThanSf=db.collection("cities") .orderBy("population") .startAt(documentSnapshot); // ... } });
Dart
db.collection("cities").doc("SF").get().then( (documentSnapshot){ finalbiggerThanSf=db .collection("cities") .orderBy("population") .startAtDocument(documentSnapshot); }, onError:(e)=>print("Error: $e"), );
Java
// Fetch the snapshot with an API call, waiting for a maximum of 30 seconds for a result.
ApiFuture<DocumentSnapshot>future=db.collection("cities").document("SF").get();
DocumentSnapshotsnapshot=future.get(30,TimeUnit.SECONDS);
// Construct the query
Queryquery=db.collection("cities").orderBy("population").startAt(snapshot);Python
doc_ref = db.collection("cities").document("SF")
snapshot = doc_ref.get()
start_at_snapshot = (
db.collection("cities").order_by("population").start_at(snapshot)
)Python
doc_ref = db.collection("cities").document("SF")
snapshot = await doc_ref.get()
start_at_snapshot = (
db.collection("cities").order_by("population").start_at(snapshot)
)C++
db->Collection("cities").Document("SF").Get().OnCompletion( [db](constFuture<DocumentSnapshot>&future){ if(future.error()==Error::kErrorOk){ constDocumentSnapshot&document_snapshot=*future.result(); Querybigger_than_sf=db->Collection("cities") .OrderBy("population") .StartAt({document_snapshot}); // ... } });
Node.js
constdocRef=db.collection('cities').doc('SF');
constsnapshot=awaitdocRef.get();
conststartAtSnapshot=db.collection('cities')
.orderBy('population')
.startAt(snapshot);
awaitstartAtSnapshot.limit(10).get();Go
cities:=client.Collection("cities")
dsnap,err:=cities.Doc("SF").Get(ctx)
iferr!=nil{
fmt.Println(err)
}
query:=cities.OrderBy("population",firestore.Asc).StartAt(dsnap.Data()["population"]).Documents(ctx)PHP
PHP
For more on installing and creating a Cloud Firestore client, refer to Cloud Firestore Client Libraries.
$citiesRef = $db->collection('samples/php/cities');
$docRef = $citiesRef->document('SF');
$snapshot = $docRef->snapshot();
$query = $citiesRef
->orderBy('population')
->startAt($snapshot);Unity
CollectionReferencecitiesRef=db.Collection("cities"); DocumentReferencedocRef=citiesRef.Document("SF"); docRef.GetSnapshotAsync().ContinueWith((snapshotTask)=> { Queryquery=citiesRef.OrderBy("Population").StartAt(snapshotTask.Result); });
C#
CollectionReferencecitiesRef=db.Collection("cities");
DocumentReferencedocRef=citiesRef.Document("SF");
DocumentSnapshotsnapshot=awaitdocRef.GetSnapshotAsync();
Queryquery=citiesRef.OrderBy("Population").StartAt(snapshot);Ruby
doc_ref=firestore.doc"#{collection_path}/SF"
snapshot=doc_ref.get
query=cities_ref.order("population").start_at(snapshot)Paginate a query
Paginate queries by combining query cursors with the limit() method.
For example, use the last document in a batch as the start of a cursor for the
next batch.
Web
import{collection,query,orderBy,startAfter,limit,getDocs}from"firebase/firestore"; // Query the first page of docs constfirst=query(collection(db,"cities"),orderBy("population"),limit(25)); constdocumentSnapshots=awaitgetDocs(first); // Get the last visible document constlastVisible=documentSnapshots.docs[documentSnapshots.docs.length-1]; console.log("last",lastVisible); // Construct a new query starting at this document, // get the next 25 cities. constnext=query(collection(db,"cities"), orderBy("population"), startAfter(lastVisible), limit(25));
Web
varfirst=db.collection("cities") .orderBy("population") .limit(25); returnfirst.get().then((documentSnapshots)=>{ // Get the last visible document varlastVisible=documentSnapshots.docs[documentSnapshots.docs.length-1]; console.log("last",lastVisible); // Construct a new query starting at this document, // get the next 25 cities. varnext=db.collection("cities") .orderBy("population") .startAfter(lastVisible) .limit(25); });
Swift
// Construct query for first 25 cities, ordered by population letfirst=db.collection("cities") .order(by:"population") .limit(to:25) first.addSnapshotListener{(snapshot,error)in guardletsnapshot=snapshotelse{ print("Error retreving cities: \(error.debugDescription)") return } guardletlastSnapshot=snapshot.documents.lastelse{ // The collection is empty. return } // Construct a new query starting after this document, // retrieving the next 25 cities. letnext=db.collection("cities") .order(by:"population") .start(afterDocument:lastSnapshot) // Use the query for pagination. // ... }
Objective-C
FIRQuery*first=[[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"population"] queryLimitedTo:25]; [firstaddSnapshotListener:^(FIRQuerySnapshot*snapshot,NSError*error){ if(snapshot==nil){ NSLog(@"Error retreiving cities: %@",error); return; } if(snapshot.documents.count==0){return;} FIRDocumentSnapshot*lastSnapshot=snapshot.documents.lastObject; // Construct a new query starting after this document, // retreiving the next 25 cities. FIRQuery*next=[[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"population"] queryStartingAfterDocument:lastSnapshot]; // Use the query for pagination. // ... }];
Kotlin
// Construct query for first 25 cities, ordered by population valfirst=db.collection("cities") .orderBy("population") .limit(25) first.get() .addOnSuccessListener{documentSnapshots-> // ... // Get the last visible document vallastVisible=documentSnapshots.documents[documentSnapshots.size()-1] // Construct a new query starting at this document, // get the next 25 cities. valnext=db.collection("cities") .orderBy("population") .startAfter(lastVisible) .limit(25) // Use the query for pagination // ... }
Java
// Construct query for first 25 cities, ordered by population Queryfirst=db.collection("cities") .orderBy("population") .limit(25); first.get() .addOnSuccessListener(newOnSuccessListener<QuerySnapshot>(){ @Override publicvoidonSuccess(QuerySnapshotdocumentSnapshots){ // ... // Get the last visible document DocumentSnapshotlastVisible=documentSnapshots.getDocuments() .get(documentSnapshots.size()-1); // Construct a new query starting at this document, // get the next 25 cities. Querynext=db.collection("cities") .orderBy("population") .startAfter(lastVisible) .limit(25); // Use the query for pagination // ... } });
Dart
// Construct query for first 25 cities, ordered by population finalfirst=db.collection("cities").orderBy("population").limit(25); first.get().then( (documentSnapshots){ // Get the last visible document finallastVisible=documentSnapshots.docs[documentSnapshots.size-1]; // Construct a new query starting at this document, // get the next 25 cities. finalnext=db .collection("cities") .orderBy("population") .startAfterDocument(lastVisible) .limit(25); // Use the query for pagination // ... }, onError:(e)=>print("Error completing: $e"), );
Java
// Construct query for first 25 cities, ordered by population.
CollectionReferencecities=db.collection("cities");
QueryfirstPage=cities.orderBy("population").limit(25);
// Wait for the results of the API call, waiting for a maximum of 30 seconds for a result.
ApiFuture<QuerySnapshot>future=firstPage.get();
List<QueryDocumentSnapshot>docs=future.get(30,TimeUnit.SECONDS).getDocuments();
// Construct query for the next 25 cities.
QueryDocumentSnapshotlastDoc=docs.get(docs.size()-1);
QuerysecondPage=cities.orderBy("population").startAfter(lastDoc).limit(25);
future=secondPage.get();
docs=future.get(30,TimeUnit.SECONDS).getDocuments();Python
cities_ref = db.collection("cities")
first_query = cities_ref.order_by("population").limit(3)
# Get the last document from the results
docs = first_query.stream()
last_doc = list(docs)[-1]
# Construct a new query starting at this document
# Note: this will not have the desired effect if
# multiple cities have the exact same population value
last_pop = last_doc.to_dict()["population"]
next_query = (
cities_ref.order_by("population").start_after({"population": last_pop}).limit(3)
)
# Use the query for pagination
# ...Python
cities_ref = db.collection("cities")
first_query = cities_ref.order_by("population").limit(3)
# Get the last document from the results
docs = [d async for d in first_query.stream()]
last_doc = list(docs)[-1]
# Construct a new query starting at this document
# Note: this will not have the desired effect if
# multiple cities have the exact same population value
last_pop = last_doc.to_dict()["population"]
next_query = (
cities_ref.order_by("population").start_after({"population": last_pop}).limit(3)
)
# Use the query for pagination
# ...C++
// Construct query for first 25 cities, ordered by population Queryfirst=db->Collection("cities").OrderBy("population").Limit(25); first.Get().OnCompletion([db](constFuture<QuerySnapshot>&future){ if(future.error()!=Error::kErrorOk){ // Handle error... return; } // Get the last visible document constQuerySnapshot&document_snapshots=*future.result(); std::vector<DocumentSnapshot>documents=document_snapshots.documents(); constDocumentSnapshot&last_visible=documents.back(); // Construct a new query starting at this document, // get the next 25 cities. Querynext=db->Collection("cities") .OrderBy("population") .StartAfter(last_visible) .Limit(25); // Use the query for pagination // ... });
Node.js
constfirst=db.collection('cities')
.orderBy('population')
.limit(3);
constsnapshot=awaitfirst.get();
// Get the last document
constlast=snapshot.docs[snapshot.docs.length-1];
// Construct a new query starting at this document.
// Note: this will not have the desired effect if multiple
// cities have the exact same population value.
constnext=db.collection('cities')
.orderBy('population')
.startAfter(last.data().population)
.limit(3);
// Use the query for pagination
// ...Go
cities:=client.Collection("cities")
// Get the first 25 cities, ordered by population.
firstPage:=cities.OrderBy("population",firestore.Asc).Limit(25).Documents(ctx)
docs,err:=firstPage.GetAll()
iferr!=nil{
returnerr
}
// Get the last document.
lastDoc:=docs[len(docs)-1]
// Construct a new query to get the next 25 cities.
secondPage:=cities.OrderBy("population",firestore.Asc).
StartAfter(lastDoc.Data()["population"]).
Limit(25)
// ...PHP
PHP
For more on installing and creating a Cloud Firestore client, refer to Cloud Firestore Client Libraries.
$citiesRef = $db->collection('samples/php/cities');
$firstQuery = $citiesRef->orderBy('population')->limit(3);
# Get the last document from the results
$documents = $firstQuery->documents();
$lastPopulation = 0;
foreach ($documents as $document) {
$lastPopulation = $document['population'];
}
# Construct a new query starting at this document
# Note: this will not have the desired effect if multiple cities have the exact same population value
$nextQuery = $citiesRef->orderBy('population')->startAfter([$lastPopulation]);
$snapshot = $nextQuery->documents();Unity
CollectionReferencecitiesRef=db.Collection("cities"); QueryfirstQuery=citiesRef.OrderBy("Population").Limit(3); // Get the last document from the results firstQuery.GetSnapshotAsync().ContinueWith((querySnapshotTask)=> { longlastPopulation=0; foreach(DocumentSnapshotdocumentSnapshotinquerySnapshotTask.Result.Documents) { lastPopulation=documentSnapshot.GetValue<long>("Population"); } // Construct a new query starting at this document. // Note: this will not have the desired effect if multiple cities have the exact same population value QuerysecondQuery=citiesRef.OrderBy("Population").StartAfter(lastPopulation); Task<QuerySnapshot>secondQuerySnapshot=secondQuery.GetSnapshotAsync();
C#
CollectionReferencecitiesRef=db.Collection("cities");
QueryfirstQuery=citiesRef.OrderBy("Population").Limit(3);
// Get the last document from the results
QuerySnapshotquerySnapshot=awaitfirstQuery.GetSnapshotAsync();
longlastPopulation=0;
foreach(DocumentSnapshotdocumentSnapshotinquerySnapshot.Documents)
{
lastPopulation=documentSnapshot.GetValue<long>("Population");
}
// Construct a new query starting at this document.
// Note: this will not have the desired effect if multiple cities have the exact same population value
QuerysecondQuery=citiesRef.OrderBy("Population").StartAfter(lastPopulation);
QuerySnapshotsecondQuerySnapshot=awaitsecondQuery.GetSnapshotAsync();Ruby
cities_ref=firestore.colcollection_path
first_query=cities_ref.order("population").limit(3)
# Get the last document from the results.
last_population=0
first_query.getdo|city|
last_population=city.data[:population]
end
# Construct a new query starting at this document.
# Note: this will not have the desired effect if multiple cities have the exact same population value.
second_query=cities_ref.order("population").start_after(last_population)
second_query.getdo|city|
puts"Document #{city.document_id} returned by paginated query cursor."
endSet cursor based on multiple fields
When using a cursor based on a field value (not a DocumentSnapshot), you can make the cursor position more precise by adding additional fields. This is particularly useful if your data set includes multiple documents that all have the same value for your cursor field, making the cursor's position ambiguous. You can add additional field values to your cursor to further specify the start or end point and reduce ambiguity.
For example, in a data set containing all the cities named "Springfield" in the United States, there would be multiple start points for a query set to start at "Springfield":
| Cities | |
|---|---|
| Name | State |
| Springfield | Massachusetts |
| Springfield | Missouri |
| Springfield | Wisconsin |
To start at a specific Springfield, you could add the state as a secondary condition in your cursor clause.
Web
// Will return all Springfields import{collection,query,orderBy,startAt}from"firebase/firestore"; constq1=query(collection(db,"cities"), orderBy("name"), orderBy("state"), startAt("Springfield")); // Will return "Springfield, Missouri" and "Springfield, Wisconsin" constq2=query(collection(db,"cities"), orderBy("name"), orderBy("state"), startAt("Springfield","Missouri"));
Web
// Will return all Springfields db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield"); // Will return "Springfield, Missouri" and "Springfield, Wisconsin" db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield","Missouri");
Swift
// Will return all Springfields db.collection("cities") .order(by:"name") .order(by:"state") .start(at:["Springfield"]) // Will return "Springfield, Missouri" and "Springfield, Wisconsin" db.collection("cities") .order(by:"name") .order(by:"state") .start(at:["Springfield","Missouri"])
Objective-C
// Will return all Springfields [[[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"name"] queryOrderedByField:@"state"] queryStartingAtValues:@[@"Springfield"]]; // Will return "Springfield, Missouri" and "Springfield, Wisconsin" [[[[dbcollectionWithPath:@"cities"] queryOrderedByField:@"name"] queryOrderedByField:@"state"] queryStartingAtValues:@[@"Springfield",@"Missouri"]];
Kotlin
// Will return all Springfields db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield") // Will return "Springfield, Missouri" and "Springfield, Wisconsin" db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield","Missouri")
Java
// Will return all Springfields db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield"); // Will return "Springfield, Missouri" and "Springfield, Wisconsin" db.collection("cities") .orderBy("name") .orderBy("state") .startAt("Springfield","Missouri");
Dart
// Will return all Springfields db .collection("cities") .orderBy("name") .orderBy("state") .startAt(["Springfield"]); // Will return "Springfield, Missouri" and "Springfield, Wisconsin" db .collection("cities") .orderBy("name") .orderBy("state") .startAt(["Springfield","Missouri"]);
Java
// Will return all Springfields
Queryquery1=db.collection("cities").orderBy("name").orderBy("state").startAt("Springfield");
// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
Queryquery2=
db.collection("cities").orderBy("name").orderBy("state").startAt("Springfield","Missouri");Python
start_at_name = (
db.collection("cities").order_by("name").start_at({"name": "Springfield"})
)
start_at_name_and_state = (
db.collection("cities")
.order_by("name")
.order_by("state")
.start_at({"name": "Springfield", "state": "Missouri"})
)Python
start_at_name = (
db.collection("cities")
.order_by("name")
.order_by("state")
.start_at({"name": "Springfield"})
)
start_at_name_and_state = (
db.collection("cities")
.order_by("name")
.order_by("state")
.start_at({"name": "Springfield", "state": "Missouri"})
)C++
// This is not yet supported.Node.js
// Will return all Springfields
conststartAtNameRes=awaitdb.collection('cities')
.orderBy('name')
.orderBy('state')
.startAt('Springfield')
.get();
// Will return 'Springfield, Missouri' and 'Springfield, Wisconsin'
conststartAtNameAndStateRes=awaitdb.collection('cities')
.orderBy('name')
.orderBy('state')
.startAt('Springfield','Missouri')
.get();Go
// Will return all Springfields.
client.Collection("cities").
OrderBy("name",firestore.Asc).
OrderBy("state",firestore.Asc).
StartAt("Springfield")
// Will return Springfields where state comes after Wisconsin.
client.Collection("cities").
OrderBy("name",firestore.Asc).
OrderBy("state",firestore.Asc).
StartAt("Springfield","Wisconsin")PHP
PHP
For more on installing and creating a Cloud Firestore client, refer to Cloud Firestore Client Libraries.
// Will return all Springfields
$query1 = $db
->collection('samples/php/cities')
->orderBy('name')
->orderBy('state')
->startAt(['Springfield']);
// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
$query2 = $db
->collection('samples/php/cities')
->orderBy('name')
->orderBy('state')
->startAt(['Springfield', 'Missouri']);Unity
Queryquery1=db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield"); Queryquery2=db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield","Missouri");
C#
Queryquery1=db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield");
Queryquery2=db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield","Missouri");Ruby
# Will return all Springfields
query1=firestore.col(collection_path).order("name").order("state").start_at("Springfield")
# Will return "Springfield, Missouri" and "Springfield, Wisconsin"
query2=firestore.col(collection_path).order("name").order("state").start_at(["Springfield","Missouri"])