Cloud Firestore의 쿼리 커서를 사용하면 쿼리에 정의한 매개변수에 따라 쿼리에서 반환하는 데이터를 일정하게 분할할 수 있습니다.
쿼리 커서로 쿼리의 시작점과 끝점을 정의하여 다음을 수행할 수 있습니다.
- 데이터 중 일부를 반환합니다.
- 쿼리 결과를 페이지화합니다.
그러나 쿼리의 범위를 구체적으로 정의하려면 단순 쿼리에서 설명하는 where()
메서드를 사용해야 합니다.
쿼리에 단순 커서 추가
startAt()
또는 startAfter()
메서드를 사용하여 쿼리의 시작점을 정의합니다.
startAt()
메서드는 시작점을 포함하고, startAfter()
메서드는 시작점을 제외합니다.
예를 들어 쿼리에 startAt(A)
을 사용하면 전체 알파벳이 반환됩니다.
startAfter(A)
를 대신 사용하면 B-Z
가 반환됩니다.
import { query, orderBy, startAt } from "firebase/firestore"; const q = query(citiesRef, orderBy("population"), startAt(1000000));
citiesRef.orderBy("population").startAt(1000000);
// Get all cities with population over one million, ordered by population. db.collection("cities") .order(by: "population") .start(at: [1000000])
// Get all cities with population over one million, ordered by population. [[[db collectionWithPath:@"cities"] queryOrderedByField:@"population"] queryStartingAtValues:@[ @1000000 ]];
// Get all cities with a population >= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .startAt(1000000)
// Get all cities with a population >= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .startAt(1000000);
db.collection("cities").orderBy("population").startAt([1000000]);
// Get all cities with a population >= 1,000,000, ordered by population, db->Collection("cities") .OrderBy("population") .StartAt({FieldValue::Integer(1000000)});
PHP
Cloud Firestore 클라이언트 설치 및 생성에 관한 자세한 내용은 Cloud Firestore 클라이언트 라이브러리를 참조하세요.
Query query = citiesRef.OrderBy("Population").StartAt(1000000);
마찬가지로 endAt()
또는 endBefore()
메서드를 사용하여 쿼리 결과에 대한 끝점을 정의합니다.
import { query, orderBy, endAt } from "firebase/firestore"; const q = query(citiesRef, orderBy("population"), endAt(1000000));
citiesRef.orderBy("population").endAt(1000000);
// Get all cities with population less than one million, ordered by population. db.collection("cities") .order(by: "population") .end(at: [1000000])
// Get all cities with population less than one million, ordered by population. [[[db collectionWithPath:@"cities"] queryOrderedByField:@"population"] queryEndingAtValues:@[ @1000000 ]];
// Get all cities with a population <= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .endAt(1000000)
// Get all cities with a population <= 1,000,000, ordered by population, db.collection("cities") .orderBy("population") .endAt(1000000);
db.collection("cities").orderBy("population").endAt([1000000]);
// Get all cities with a population <= 1,000,000, ordered by population, db->Collection("cities") .OrderBy("population") .EndAt({FieldValue::Integer(1000000)});
PHP
Cloud Firestore 클라이언트 설치 및 생성에 관한 자세한 내용은 Cloud Firestore 클라이언트 라이브러리를 참조하세요.
Query query = citiesRef.OrderBy("Population").EndAt(1000000);
문서 스냅샷을 사용하여 쿼리 커서 정의
문서 스냅샷을 쿼리 커서의 시작점이나 끝점으로 커서 절에 전달할 수도 있습니다. 문서 스냅샷의 값은 쿼리 커서의 값으로 사용됩니다.
예를 들어 여러 도시와 인구로 구성된 데이터 세트 중 '샌프란시스코' 문서의 스냅샷을 만듭니다. 그런 다음 이 문서 스냅샷을 인구 쿼리 커서의 시작점으로 사용합니다. 이렇게 하면 문서 스냅샷에 정의된 San Francisco의 인구보다 인구가 더 많거나 같은 도시가 모두 반환됩니다.
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)); // ...
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); // ... });
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) }
[[[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]; }];
// 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) // ... }
// 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); // ... } });
db.collection("cities").doc("SF").get().then( (documentSnapshot) { final biggerThanSf = db .collection("cities") .orderBy("population") .startAtDocument(documentSnapshot); }, onError: (e) => print("Error: $e"), );
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}); // ... } });
PHP
Cloud Firestore 클라이언트 설치 및 생성에 관한 자세한 내용은 Cloud Firestore 클라이언트 라이브러리를 참조하세요.
CollectionReference citiesRef = db.Collection("cities"); DocumentReference docRef = citiesRef.Document("SF"); docRef.GetSnapshotAsync().ContinueWith((snapshotTask) => { Query query = citiesRef.OrderBy("Population").StartAt(snapshotTask.Result); });
쿼리 페이지화
쿼리 커서를 limit()
메서드와 결합하여 쿼리를 페이지화합니다.
예를 들어 일괄 처리 분량의 마지막 문서를 다음 일괄 처리 분량의 커서 시작점으로 사용합니다.
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));
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); });
// 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. // ... }
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. // ... }];
// 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 // ... }
// 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 // ... } });
// 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") .startAfterDocument(lastVisible) .limit(25); // Use the query for pagination // ... }, onError: (e) => print("Error completing: $e"), );
// 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 // ... });
PHP
Cloud Firestore 클라이언트 설치 및 생성에 관한 자세한 내용은 Cloud Firestore 클라이언트 라이브러리를 참조하세요.
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();
여러 필드를 기준으로 커서 설정
(문서 스냅샷이 아닌) 필드 값을 기준으로 커서를 사용할 경우 필드를 더 추가하여 커서 위치를 더욱 정확하게 지정할 수 있습니다. 이 방법은 데이터 세트에 커서 필드의 값이 동일한 문서가 여러 개 있어 커서 위치가 불분명할 때 특히 유용합니다. 커서에 추가 필드 값을 추가하여 시작점 또는 끝점을 추가로 지정하면 모호성을 줄일 수 있습니다.
예를 들어 미국의 'Springfield'라는 도시를 모두 포함하는 데이터 세트에서 쿼리가 'Springfield'에서 시작되도록 설정하면 시작점이 여러 개 생깁니다.
도시 | |
---|---|
이름 | 주 |
Springfield | 메사추세츠 |
Springfield | 미주리 |
Springfield | 위스콘신 |
커서 절에 '주'를 2차 조건으로 추가하면 Springfield의 시작점을 더 구체적으로 지정할 수 있습니다.
// 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"));
// 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 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"])
// 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" ]];
// 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 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 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"]);
// This is not yet supported.
PHP
Cloud Firestore 클라이언트 설치 및 생성에 관한 자세한 내용은 Cloud Firestore 클라이언트 라이브러리를 참조하세요.
Query query1 = db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield"); Query query2 = db.Collection("cities").OrderBy("Name").OrderBy("State").StartAt("Springfield", "Missouri");