2022년 10월 18일에 오프라인과 온라인으로 진행될 Firebase Summit에 참여하세요. Firebase로 앱을 빠르게 개발하고 안심하고 앱을 출시하며 손쉽게 확장하는 방법을 알아보세요. 지금 등록하기

쿼리 커서로 데이터 페이지화

Cloud Firestore의 쿼리 커서를 사용하면 쿼리에 정의한 매개변수에 따라 쿼리에서 반환하는 데이터를 일정하게 분할할 수 있습니다.

쿼리 커서로 쿼리의 시작점과 끝점을 정의하여 다음을 수행할 수 있습니다.

  • 데이터 중 일부를 반환합니다.
  • 쿼리 결과를 페이지화합니다.

그러나 쿼리의 범위를 구체적으로 정의하려면 단순 쿼리에서 설명하는 where() 메서드를 사용해야 합니다.

쿼리에 단순 커서 추가

startAt() 또는 startAfter() 메서드를 사용하여 쿼리의 시작점을 정의합니다. startAt() 메서드는 시작점을 포함하고, startAfter() 메서드는 시작점을 제외합니다.

예를 들어 쿼리에 startAt(A)을 사용하면 전체 알파벳이 반환됩니다. startAfter(A)를 대신 사용하면 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
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Get all cities with population over one million, ordered by population.
db.collection("cities")
    .order(by: "population")
    .start(at: [1000000])
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Get all cities with population over one million, ordered by population.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryStartingAtValues:@[ @1000000 ]];

Java

// Get all cities with a population >= 1,000,000, ordered by population,
db.collection("cities")
        .orderBy("population")
        .startAt(1000000);

Kotlin+KTX

// 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]);
자바
Query query = cities.orderBy("population").startAt(4921000L);
Python
cities_ref = db.collection(u'cities')
query_start_at = cities_ref.order_by(u'population').start_at({
    u'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
const startAtRes = await db.collection('cities')
  .orderBy('population')
  .startAt(1000000)
  .get();
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).StartAt(1000000)
PHP
$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)

마찬가지로 endAt() 또는 endBefore() 메서드를 사용하여 쿼리 결과에 대한 끝점을 정의합니다.

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
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Get all cities with population less than one million, ordered by population.
db.collection("cities")
    .order(by: "population")
    .end(at: [1000000])
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Get all cities with population less than one million, ordered by population.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryEndingAtValues:@[ @1000000 ]];

Java

// Get all cities with a population <= 1,000,000, ordered by population,
db.collection("cities")
        .orderBy("population")
        .endAt(1000000);

Kotlin+KTX

// 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]);
자바
Query query = cities.orderBy("population").endAt(4921000L);
Python
cities_ref = db.collection(u'cities')
query_end_at = cities_ref.order_by(u'population').end_at({
    u'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
const endAtRes = await db.collection('cities')
  .orderBy('population')
  .endAt(1000000)
  .get();
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).EndAt(1000000)
PHP
$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)

문서 스냅샷을 사용하여 쿼리 커서 정의

문서 스냅샷을 쿼리 커서의 시작점이나 끝점으로 커서 절에 전달할 수도 있습니다. 문서 스냅샷의 값은 쿼리 커서의 값으로 사용됩니다.

예를 들어 여러 도시와 인구로 구성된 데이터 세트 중 '샌프란시스코' 문서의 스냅샷을 만듭니다. 그런 다음 이 문서 스냅샷을 인구 쿼리 커서의 시작점으로 사용합니다. 이렇게 하면 문서 스냅샷에 정의된 샌프란시스코의 인구보다 인구가 더 많거나 같은 도시가 모두 반환됩니다.

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));
// ...

Web version 8

var citiesRef = db.collection("cities");

return citiesRef.doc("SF").get().then((doc) => {
    // Get all cities with a population bigger than San Francisco
    var biggerThanSf = citiesRef
        .orderBy("population")
        .startAt(doc);

    // ...
});
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
db.collection("cities")
    .document("SF")
    .addSnapshotListener { (document, error) in
        guard let document = document else {
            print("Error retreving cities: \(error.debugDescription)")
            return
        }

        // Get all cities with a population greater than or equal to San Francisco.
        let sfSizeOrBigger = db.collection("cities")
            .order(by: "population")
            .start(atDocument: document)
}
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
[[[db collectionWithPath:@"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 = [[[db collectionWithPath:@"cities"]
          queryOrderedByField:@"population"]
          queryStartingAtDocument:snapshot];
    }];

Java

// Get the data for "San Francisco"
db.collection("cities").document("SF")
        .get()
        .addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
            @Override
            public void onSuccess(DocumentSnapshot documentSnapshot) {
                // Get all cities with a population bigger than San Francisco.
                Query biggerThanSf = db.collection("cities")
                        .orderBy("population")
                        .startAt(documentSnapshot);

                // ...
            }
        });

Kotlin+KTX

// Get the data for "San Francisco"
db.collection("cities").document("SF")
        .get()
        .addOnSuccessListener { documentSnapshot ->
            // Get all cities with a population bigger than San Francisco.
            val biggerThanSf = db.collection("cities")
                    .orderBy("population")
                    .startAt(documentSnapshot)

            // ...
        }

Dart

db.collection("cities").doc("SF").get().then(
  (documentSnapshot) {
    final biggerThanSf = db
        .collection("cities")
        .orderBy("population")
        .startAt([documentSnapshot]);
  },
  onError: (e) => print("Error: $e"),
);
자바
// 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();
DocumentSnapshot snapshot = future.get(30, TimeUnit.SECONDS);

// Construct the query
Query query = db.collection("cities").orderBy("population").startAt(snapshot);
Python
doc_ref = db.collection(u'cities').document(u'SF')

snapshot = doc_ref.get()
start_at_snapshot = db.collection(
    u'cities').order_by(u'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](const Future<DocumentSnapshot>& future) {
      if (future.error() == Error::kErrorOk) {
        const DocumentSnapshot& document_snapshot = *future.result();
        Query bigger_than_sf = db->Collection("cities")
                                   .OrderBy("population")
                                   .StartAt({document_snapshot});
        // ...
      }
    });
Node.js
const docRef = db.collection('cities').doc('SF');
const snapshot = await docRef.get();
const startAtSnapshot = db.collection('cities')
  .orderBy('population')
  .startAt(snapshot);

await startAtSnapshot.limit(10).get();
Go
cities := client.Collection("cities")
dsnap, err := cities.Doc("SF").Get(ctx)
if err != nil {
	fmt.Println(err)
}
query := cities.OrderBy("population", firestore.Asc).StartAt(dsnap.Data()["population"]).Documents(ctx)
PHP
$citiesRef = $db->collection('samples/php/cities');
$docRef = $citiesRef->document('SF');
$snapshot = $docRef->snapshot();

$query = $citiesRef
    ->orderBy('population')
    ->startAt($snapshot);
Unity
CollectionReference citiesRef = db.Collection("cities");
DocumentReference docRef = citiesRef.Document("SF");
docRef.GetSnapshotAsync().ContinueWith((snapshotTask) =>
{
    Query query = citiesRef.OrderBy("Population").StartAt(snapshotTask.Result);
});
C#
CollectionReference citiesRef = db.Collection("cities");
DocumentReference docRef = citiesRef.Document("SF");
DocumentSnapshot snapshot = await docRef.GetSnapshotAsync();
Query query = 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)

쿼리 페이지화

쿼리 커서를 limit() 메서드와 결합하여 쿼리를 페이지화합니다. 예를 들어 일괄 처리 분량의 마지막 문서를 다음 일괄 처리 분량의 커서 시작점으로 사용합니다.

Web version 9

import { collection, query, orderBy, startAfter, limit, getDocs } from "firebase/firestore";

// Query the first page of docs
const first = query(collection(db, "cities"), orderBy("population"), limit(25));
const documentSnapshots = await getDocs(first);

// Get the last visible document
const lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
console.log("last", lastVisible);

// Construct a new query starting at this document,
// get the next 25 cities.
const next = query(collection(db, "cities"),
    orderBy("population"),
    startAfter(lastVisible),
    limit(25));

Web version 8

var first = db.collection("cities")
        .orderBy("population")
        .limit(25);

return first.get().then((documentSnapshots) => {
  // Get the last visible document
  var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
  console.log("last", lastVisible);

  // Construct a new query starting at this document,
  // get the next 25 cities.
  var next = db.collection("cities")
          .orderBy("population")
          .startAfter(lastVisible)
          .limit(25);
});
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Construct query for first 25 cities, ordered by population
let first = db.collection("cities")
    .order(by: "population")
    .limit(to: 25)

first.addSnapshotListener { (snapshot, error) in
    guard let snapshot = snapshot else {
        print("Error retreving cities: \(error.debugDescription)")
        return
    }

    guard let lastSnapshot = snapshot.documents.last else {
        // The collection is empty.
        return
    }

    // Construct a new query starting after this document,
    // retrieving the next 25 cities.
    let next = db.collection("cities")
        .order(by: "population")
        .start(afterDocument: lastSnapshot)

    // Use the query for pagination.
    // ...
}
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
FIRQuery *first = [[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryLimitedTo:25];
[first addSnapshotListener:^(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 = [[[db collectionWithPath:@"cities"]
      queryOrderedByField:@"population"]
      queryStartingAfterDocument:lastSnapshot];
  // Use the query for pagination.
  // ...
}];

Java

// Construct query for first 25 cities, ordered by population
Query first = db.collection("cities")
        .orderBy("population")
        .limit(25);

first.get()
    .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot documentSnapshots) {
            // ...

            // Get the last visible document
            DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
                    .get(documentSnapshots.size() -1);

            // Construct a new query starting at this document,
            // get the next 25 cities.
            Query next = db.collection("cities")
                    .orderBy("population")
                    .startAfter(lastVisible)
                    .limit(25);

            // Use the query for pagination
            // ...
        }
    });

Kotlin+KTX

// Construct query for first 25 cities, ordered by population
val first = db.collection("cities")
        .orderBy("population")
        .limit(25)

first.get()
        .addOnSuccessListener { documentSnapshots ->
            // ...

            // Get the last visible document
            val lastVisible = documentSnapshots.documents[documentSnapshots.size() - 1]

            // Construct a new query starting at this document,
            // get the next 25 cities.
            val next = db.collection("cities")
                    .orderBy("population")
                    .startAfter(lastVisible)
                    .limit(25)

            // Use the query for pagination
            // ...
        }

Dart

// Construct query for first 25 cities, ordered by population
final first = db.collection("cities").orderBy("population").limit(25);

first.get().then(
  (documentSnapshots) {
    // Get the last visible document
    final lastVisible = documentSnapshots.docs[documentSnapshots.size - 1];

    // Construct a new query starting at this document,
    // get the next 25 cities.
    final next = db
        .collection("cities")
        .orderBy("population")
        .startAfter([lastVisible]).limit(25);

    // Use the query for pagination
    // ...
  },
  onError: (e) => print("Error completing: $e"),
);
자바
// Construct query for first 25 cities, ordered by population.
CollectionReference cities = db.collection("cities");
Query firstPage = 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.
QueryDocumentSnapshot lastDoc = docs.get(docs.size() - 1);
Query secondPage = cities.orderBy("population").startAfter(lastDoc).limit(25);

future = secondPage.get();
docs = future.get(30, TimeUnit.SECONDS).getDocuments();
Python
cities_ref = db.collection(u'cities')
first_query = cities_ref.order_by(u'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()[u'population']

next_query = (
    cities_ref
    .order_by(u'population')
    .start_after({
        u'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
Query first = db->Collection("cities").OrderBy("population").Limit(25);

first.Get().OnCompletion([db](const Future<QuerySnapshot>& future) {
  if (future.error() != Error::kErrorOk) {
    // Handle error...
    return;
  }

  // Get the last visible document
  const QuerySnapshot& document_snapshots = *future.result();
  std::vector<DocumentSnapshot> documents = document_snapshots.documents();
  const DocumentSnapshot& last_visible = documents.back();

  // Construct a new query starting at this document,
  // get the next 25 cities.
  Query next = db->Collection("cities")
                   .OrderBy("population")
                   .StartAfter(last_visible)
                   .Limit(25);

  // Use the query for pagination
  // ...
});
Node.js
const first = db.collection('cities')
  .orderBy('population')
  .limit(3);

const snapshot = await first.get();

// Get the last document
const last = 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.
const next = 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()
if err != nil {
	return err
}

// 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
$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
CollectionReference citiesRef = db.Collection("cities");
Query firstQuery = citiesRef.OrderBy("Population").Limit(3);

// Get the last document from the results
firstQuery.GetSnapshotAsync().ContinueWith((querySnapshotTask) =>
{
    long lastPopulation = 0;
    foreach (DocumentSnapshot documentSnapshot in querySnapshotTask.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
    Query secondQuery = citiesRef.OrderBy("Population").StartAfter(lastPopulation);
    Task<QuerySnapshot> secondQuerySnapshot = secondQuery.GetSnapshotAsync();
C#
CollectionReference citiesRef = db.Collection("cities");
Query firstQuery = citiesRef.OrderBy("Population").Limit(3);

// Get the last document from the results
QuerySnapshot querySnapshot = await firstQuery.GetSnapshotAsync();
long lastPopulation = 0;
foreach (DocumentSnapshot documentSnapshot in querySnapshot.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
Query secondQuery = citiesRef.OrderBy("Population").StartAfter(lastPopulation);
QuerySnapshot secondQuerySnapshot = await secondQuery.GetSnapshotAsync();
Ruby
cities_ref  = firestore.col collection_path
first_query = cities_ref.order("population").limit(3)

# Get the last document from the results.
last_population = 0
first_query.get do |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.get do |city|
  puts "Document #{city.document_id} returned by paginated query cursor."
end

여러 필드를 기준으로 커서 설정

(문서 스냅샷이 아닌) 필드 값을 기준으로 커서를 사용할 경우 필드를 더 추가하여 커서 위치를 더욱 정확하게 지정할 수 있습니다. 이 방법은 데이터 세트에 커서 필드의 값이 동일한 문서가 여러 개 있어 커서 위치가 불분명할 때 특히 유용합니다. 커서에 추가 필드 값을 추가하여 시작점 또는 끝점을 추가로 지정하면 모호성을 줄일 수 있습니다.

예를 들어 미국의 'Springfield'라는 도시를 모두 포함하는 데이터 세트에서 쿼리가 'Springfield'에서 시작되도록 설정하면 시작점이 여러 개 생깁니다.

도시
이름
Springfield Massachusetts
Springfield Missouri
Springfield Wisconsin

커서 절에 '주'를 2차 조건으로 추가하면 Springfield의 시작점을 더 구체적으로 지정할 수 있습니다.

Web version 9

// Will return all Springfields
import { collection, query, orderBy, startAt } from "firebase/firestore";
const q1 = query(collection(db, "cities"),
   orderBy("name"),
   orderBy("state"),
   startAt("Springfield"));

// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
const q2 = query(collection(db, "cities"),
   orderBy("name"),
   orderBy("state"),
   startAt("Springfield", "Missouri"));

Web version 8

// 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
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// 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
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Will return all Springfields
[[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"name"]
    queryOrderedByField:@"state"]
    queryStartingAtValues:@[ @"Springfield" ]];
// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
[[[[db collectionWithPath:@"cities"]
   queryOrderedByField:@"name"]
   queryOrderedByField:@"state"]
   queryStartingAtValues:@[ @"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");

Kotlin+KTX

// 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"]);
자바
// Will return all Springfields
Query query1 = db.collection("cities").orderBy("name").orderBy("state").startAt("Springfield");

// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
Query query2 =
    db.collection("cities").orderBy("name").orderBy("state").startAt("Springfield", "Missouri");
Python
start_at_name = (
    db.collection(u'cities')
    .order_by(u'name')
    .start_at({
        u'name': u'Springfield'
    })
)

start_at_name_and_state = (
    db.collection(u'cities')
    .order_by(u'name')
    .order_by(u'state')
    .start_at({
        u'name': u'Springfield',
        u'state': u'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
const startAtNameRes = await db.collection('cities')
  .orderBy('name')
  .orderBy('state')
  .startAt('Springfield')
  .get();

// Will return 'Springfield, Missouri' and 'Springfield, Wisconsin'
const startAtNameAndStateRes = await db.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
// 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
Query query1 = db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield");
Query query2 = db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield", "Missouri");
C#
Query query1 = db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield");
Query query2 = 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"])