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

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

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

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

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

쿼리에 단순 커서 추가

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

예를 들어 쿼리에 startAt(A)을 사용하면 전체 알파벳이 반환됩니다. startAfter(A)를 대신 사용하면 B-Z가 반환됩니다.

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.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryStartingAtValues:@[ @1000000 ]];
  
Android
// Get all cities with a population >= 1,000,000, ordered by population,
db.collection("cities")
        .orderBy("population")
        .startAt(1000000);
자바
Query query = cities.orderBy("population").startAt(4921000L);
Python
// Python snippet missing
Node.js
var startAt = db.collection('cities')
    .orderBy('population')
    .startAt(1000000);
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).StartAt(1000000)
PHP
$query = $citiesRef
    ->orderBy('population')
    ->startAt([1000000]);

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

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.
[[[db collectionWithPath:@"cities"]
    queryOrderedByField:@"population"]
    queryEndingAtValues:@[ @1000000 ]];
  
Android
// Get all cities with a population <= 1,000,000, ordered by population,
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
})
Node.js
var endAt = db.collection('cities')
    .orderBy('population')
    .endAt(1000000);
Go
query := client.Collection("cities").OrderBy("population", firestore.Asc).EndAt(1000000)
PHP
$query = $citiesRef
    ->orderBy('population')
    ->endAt([1000000]);

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

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

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

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

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

    // ...
});
Swift
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
[[[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];
    }];
  
Android
// 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);

                // ...
            }
        });
자바
// Not supported in Java SDK
Python
# Not supported in Python SDK
Node.js
// Not supported in Node.js SDK
Go
// Not supported in Go SDK
PHP
// Not supported in PHP SDK

쿼리 페이지화

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

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

return first.get().then(function (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
// 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
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.
  // ...
}];
  
Android
// 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
            // ...
        }
    });
자바
// Not supported in Java SDK
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.get()
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
# ...
Node.js
var first = db.collection('cities')
    .orderBy('population')
    .limit(3);

var paginate = first.get()
    .then((snapshot) => {
      // ...

      // Get the last document
      var 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.
      var 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('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();

여러 커서 조건 설정

커서의 시작점이나 끝점을 보다 세밀하게 정하려면 커서 절에 여러 조건을 지정할 수 있습니다. 이 방법은 커서 절의 첫 번째 조건으로 여러 결과가 반환되는 필드가 데이터 세트에 포함된 경우에 특히 유용합니다. 여러 조건으로 시작점이나 끝점을 더 구체적으로 지정하여 모호성을 줄일 수 있습니다.

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

도시
이름
Springfield Massachusetts
Springfield Missouri
Springfield Wisconsin

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

// 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
[[[[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" ]];
  
Android
// 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')
    .order_by(u'state')
    .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'
    })
)
Node.js
// Will return all Springfields
var startAtName = db.collection('cities')
    .orderBy('name')
    .orderBy('state')
    .startAt('Springfield');
// Will return 'Springfield, Missouri' and 'Springfield, Wisconsin'
var startAtNameAndState = db.collection('cities')
    .orderBy('name')
    .orderBy('state')
    .startAt('Springfield', 'Missouri');
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('cities')
    ->orderBy('name')
    ->orderBy('state')
    ->startAt(['Springfield']);

// Will return "Springfield, Missouri" and "Springfield, Wisconsin"
$query2 = $db
    ->collection('cities')
    ->orderBy('name')
    ->orderBy('state')
    ->startAt(['Springfield', 'Missouri']);

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.