콘솔로 이동

Cloud Firestore에서 간단한 쿼리 및 복합 쿼리 실행

Cloud Firestore는 컬렉션에서 검색할 문서를 지정하는 강력한 쿼리 기능을 제공합니다. 데이터 가져오기실시간 업데이트 가져오기의 설명에 따라 이러한 쿼리를 get() 또는 addSnapshotListener()와 함께 사용할 수도 있습니다.

예시 데이터

우선 도시에 관한 데이터를 작성하여 이후 다양한 방법으로 데이터 읽는 방법을 살펴보겠습니다.

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

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000 });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000 });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000 });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000 });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000 });
Swift
let citiesRef = db.collection("cities")

citiesRef.document("SF").setData([
    "name": "San Francisco",
    "state": "CA",
    "country": "USA",
    "capital": false,
    "population": 860000
    ])
citiesRef.document("LA").setData([
    "name": "Los Angeles",
    "state": "CA",
    "country": "USA",
    "capital": false,
    "population": 3900000
    ])
citiesRef.document("DC").setData([
    "name": "Washington D.C.",
    "country": "USA",
    "capital": true,
    "population": 680000
    ])
citiesRef.document("TOK").setData([
    "name": "Tokyo",
    "country": "Japan",
    "capital": true,
    "population": 9000000
    ])
citiesRef.document("BJ").setData([
    "name": "Beijing",
    "country": "China",
    "capital": true,
    "population": 21500000
    ])
Objective-C
FIRCollectionReference *citiesRef = [self.db collectionWithPath:@"cities"];
[[citiesRef documentWithPath:@"SF"] setData:@{
  @"name": @"San Francisco",
  @"state": @"CA",
  @"country": @"USA",
  @"capital": @(NO),
  @"population": @860000
}];
[[citiesRef documentWithPath:@"LA"] setData:@{
  @"name": @"Los Angeles",
  @"state": @"CA",
  @"country": @"USA",
  @"capital": @(NO),
  @"population": @3900000
}];
[[citiesRef documentWithPath:@"DC"] setData:@{
  @"name": @"Washington D.C.",
  @"country": @"USA",
  @"capital": @(YES),
  @"population": @680000
}];
[[citiesRef documentWithPath:@"TOK"] setData:@{
  @"name": @"Tokyo",
  @"country": @"Japan",
  @"capital": @(YES),
  @"population": @9000000
}];
[[citiesRef documentWithPath:@"BJ"] setData:@{
  @"name": @"Beijing",
  @"country": @"China",
  @"capital": @(YES),
  @"population": @21500000
}];
  
Android
CollectionReference cities = db.collection("cities");

Map<String, Object> data1 = new HashMap<>();
data1.put("name", "San Francisco");
data1.put("state", "CA");
data1.put("country", "USA");
data1.put("capital", false);
data1.put("population", 860000);
cities.document("SF").set(data1);

Map<String, Object> data2 = new HashMap<>();
data2.put("name", "Los Angeles");
data2.put("state", "CA");
data2.put("country", "USA");
data2.put("capital", false);
data2.put("population", 3900000);
cities.document("LA").set(data2);

Map<String, Object> data3 = new HashMap<>();
data3.put("name", "Washington D.C.");
data3.put("state", null);
data3.put("country", "USA");
data3.put("capital", true);
data3.put("population", 680000);
cities.document("DC").set(data3);

Map<String, Object> data4 = new HashMap<>();
data4.put("name", "Tokyo");
data4.put("state", null);
data4.put("country", "Japan");
data4.put("capital", true);
data4.put("population", 9000000);
cities.document("TOK").set(data4);

Map<String, Object> data5 = new HashMap<>();
data5.put("name", "Beijing");
data5.put("state", null);
data5.put("country", "China");
data5.put("capital", true);
data5.put("population", 21500000);
cities.document("BJ").set(data5);
자바
CollectionReference cities = db.collection("cities");
List<ApiFuture<WriteResult>> futures = new ArrayList<>();
futures.add(cities.document("SF").set(new City("San Francisco", "CA", "USA", false, 860000L)));
futures.add(cities.document("LA").set(new City("Los Angeles", "CA", "USA", false, 3900000L)));
futures.add(cities.document("DC").set(new City("Washington D.C.", null, "USA", true, 680000L)));
futures.add(cities.document("TOK").set(new City("Tokyo", null, "Japan", true, 9000000L)));
futures.add(cities.document("BJ").set(new City("Beijing", null, "China", true, 21500000L)));
// (optional) block on documents successfully added
ApiFutures.allAsList(futures).get();
Python
class City(object):
    def __init__(self, name, state, country, capital=False, population=0):
        self.name = name
        self.state = state
        self.country = country
        self.capital = capital
        self.population = population

    @staticmethod
    def from_dict(source):
        # ...

    def to_dict(self):
        # ...

    def __repr__(self):
        return u'City(name={}, country={}, population={}, capital={})'.format(
            self.name, self.country, self.population, self.capital)
cities_ref = db.collection(u'cities')
cities_ref.document(u'SF').set(
    City(u'San Francisco', u'CA', u'USA', False, 860000).to_dict())
cities_ref.document(u'LA').set(
    City(u'Los Angeles', u'CA', u'USA', False, 3900000).to_dict())
cities_ref.document(u'DC').set(
    City(u'Washington D.C.', None, u'USA', True, 680000).to_dict())
cities_ref.document(u'TOK').set(
    City(u'Tokyo', None, u'Japan', True, 9000000).to_dict())
cities_ref.document(u'BJ').set(
    City(u'Beijing', None, u'China', True, 21500000).to_dict())
Node.js
var citiesRef = db.collection('cities');

var setSf = citiesRef.doc('SF').set({
    name: 'San Francisco', state: 'CA', country: 'USA',
    capital: false, population: 860000 });
var setLa = citiesRef.doc('LA').set({
    name: 'Los Angeles', state: 'CA', country: 'USA',
    capital: false, population: 3900000 });
var setDc = citiesRef.doc('DC').set({
    name: 'Washington, D.C.', state: null, country: 'USA',
    capital: true, population: 680000 });
var setTok = citiesRef.doc('TOK').set({
    name: 'Tokyo', state: null, country: 'Japan',
    capital: true, population: 9000000 });
var setBj = citiesRef.doc('BJ').set({
    name: 'Beijing', state: null, country: 'China',
    capital: true, population: 21500000 });
Go
cities := []struct {
	id string
	c  City
}{
	{id: "SF", c: City{Name: "San Francisco", State: "CA", Country: "USA", Capital: false, Population: 860000}},
	{id: "LA", c: City{Name: "Los Angeles", State: "CA", Country: "USA", Capital: false, Population: 3900000}},
	{id: "DC", c: City{Name: "Washington D.C.", Country: "USA", Capital: false, Population: 680000}},
	{id: "TOK", c: City{Name: "Tokyo", Country: "Japan", Capital: true, Population: 9000000}},
	{id: "BJ", c: City{Name: "Beijing", Country: "China", Capital: true, Population: 21500000}},
}
for _, c := range cities {
	if _, err := client.Collection("cities").Doc(c.id).Set(ctx, c.c); err != nil {
		return err
	}
}
PHP
$citiesRef = $db->collection('cities');
$citiesRef->document('SF')->set([
    'name' => 'San Francisco',
    'state' => 'CA',
    'country' => 'USA',
    'capital' => false,
    'population' => 860000
]);
$citiesRef->document('LA')->set([
    'name' => 'Los Angeles',
    'state' => 'CA',
    'country' => 'USA',
    'capital' => false,
    'population' => 3900000
]);
$citiesRef->document('DC')->set([
    'name' => 'Washington D.C.',
    'state' => null,
    'country' => 'USA',
    'capital' => true,
    'population' => 680000
]);
$citiesRef->document('TOK')->set([
    'name' => 'Tokyo',
    'state' => null,
    'country' => 'Japan',
    'capital' => true,
    'population' => 9000000
]);
$citiesRef->document('BJ')->set([
    'name' => 'Beijing',
    'state' => null,
    'country' => 'China',
    'capital' => true,
    'population' => 21500000
]);
printf('Added example cities data to the cities collection.' . PHP_EOL);

간단한 쿼리

다음 쿼리는 CA 주 내의 모든 도시를 반환합니다.

// Create a reference to the cities collection
var citiesRef = db.collection("cities");

// Create a query against the collection.
var query = citiesRef.where("state", "==", "CA");
Swift
// Create a reference to the cities collection
let citiesRef = db.collection("cities")

// Create a query against the collection.
let query = citiesRef.whereField("state", isEqualTo: "CA")
Objective-C
// Create a reference to the cities collection
FIRCollectionReference *citiesRef = [self.db collectionWithPath:@"cities"];
// Create a query against the collection.
FIRQuery *query = [citiesRef queryWhereField:@"state" isEqualTo:@"CA"];
  
Android
// Create a reference to the cities collection
CollectionReference citiesRef = db.collection("cities");

// Create a query against the collection.
Query query = citiesRef.whereEqualTo("state", "CA");
자바
// Create a reference to the cities collection
CollectionReference cities = db.collection("cities");
// Create a query against the collection.
Query query = cities.whereEqualTo("state", "CA");
// retrieve  query results asynchronously using query.get()
ApiFuture<QuerySnapshot> querySnapshot = query.get();

for (DocumentSnapshot document : querySnapshot.get().getDocuments()) {
  System.out.println(document.getId());
}
Python
# Create a reference to the cities collection
cities_ref = db.collection(u'cities')

# Create a query against the collection
query_ref = cities_ref.where(u'state', u'==', u'CA')
Node.js
// Create a reference to the cities collection
var citiesRef = db.collection('cities');

// Create a query against the collection
var queryRef = citiesRef.where('state', '==', 'CA');
Go
query := client.Collection("cities").Where("state", "==", "CA")
PHP
$citiesRef = $db->collection('cities');
$query = $citiesRef->where('state', '=', 'CA');
$snapshot = $query->documents();
foreach ($snapshot as $document) {
    printf('Document %s returned by query state=CA' . PHP_EOL, $document->id());
}

다음 쿼리는 모든 주도를 반환합니다.

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

var query = citiesRef.where("capital", "==", true);
Swift
let capitalCities = db.collection("cities").whereField("capital", isEqualTo: true)
Objective-C
FIRQuery *capitalCities =
    [[self.db collectionWithPath:@"cities"] queryWhereField:@"capital" isEqualTo:@YES];
  
Android
Query capitalCities = db.collection("cities").whereEqualTo("capital", true);
자바
// Create a reference to the cities collection
CollectionReference cities = db.collection("cities");
// Create a query against the collection.
Query query = cities.whereEqualTo("capital", true);
// retrieve  query results asynchronously using query.get()
ApiFuture<QuerySnapshot> querySnapshot = query.get();

for (DocumentSnapshot document : querySnapshot.get().getDocuments()) {
  System.out.println(document.getId());
}
Python
cities_ref = db.collection(u'cities')

query = cities_ref.where(u'capital', u'==', True)
Node.js
// Create a reference to the cities collection
var citiesRef = db.collection('cities');

// Create a query against the collection
var queryRef = citiesRef.where('capital', '==', true);
Go
query := client.Collection("cities").Where("capital", "==", true)
PHP
$citiesRef = $db->collection('cities');
$query = $citiesRef->where('capital', '=', true);
$snapshot = $query->documents();
foreach ($snapshot as $document) {
    printf('Document %s returned by query capital=true' . PHP_EOL, $document->id());
}

where() 메소드는 필터링할 필드, 비교 연산, 값 등 3가지 매개변수를 취합니다. 비교는 <, <=, ==, > 또는 >=일 수 있습니다. iOS, Android 및 자바의 경우 메소드에서 명시적으로 비교 연산자의 이름이 지정됩니다.

몇 가지 필터링 예는 다음과 같습니다.

citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")
Swift
citiesRef.whereField("state", isEqualTo: "CA")
citiesRef.whereField("population", isLessThan: 100000)
citiesRef.whereField("name", isGreaterThanOrEqualTo: "San Francisco")
Objective-C
[citiesRef queryWhereField:@"state" isEqualTo:@"CA"];
[citiesRef queryWhereField:@"population" isLessThan:@100000];
[citiesRef queryWhereField:@"name" isGreaterThanOrEqualTo:@"San Francisco"];
  
Android
citiesRef.whereEqualTo("state", "CA");
citiesRef.whereLessThan("population", 100000);
citiesRef.whereGreaterThanOrEqualTo("name", "San Francisco");
자바
Query countryQuery = cities.whereEqualTo("state", "CA");
Query populationQuery = cities.whereLessThan("population", 1000000L);
Query cityQuery = cities.whereGreaterThanOrEqualTo("name", "San Francisco");
Python
cities_ref = db.collection(u'cities')

cities_ref.where(u'state', u'==', u'CA')
cities_ref.where(u'population', u'<', 1000000)
cities_ref.where(u'name', u'>=', u'San Francisco')
Node.js
var brazilCities = citiesRef.where('state', '==', 'CA');
var smallCities = citiesRef.where('population', '<', 1000000);
var afterParis = citiesRef.where('name', '>=', 'San Francisco');
Go
countryQuery := cities.Where("state", "==", "CA")
popQuery := cities.Where("population", "<", 1000000)
cityQuery := cities.Where("name", ">=", "San Francisco")
PHP
$stateQuery = $citiesRef->where('state', '=', 'CA');
$populationQuery = $citiesRef->where('population', '>', 1000000);
$nameQuery = $citiesRef->where('name', '>=', 'San Francisco');

복합 쿼리

또한 여러 where() 메소드를 연결하여 보다 구체적인 쿼리(논리적 AND)를 만들 수 있습니다. 하지만 등호 연산자(==)를 범위 비교(<, <=, > 또는 >=)와 결합하려면 맞춤 색인을 만들어야 합니다.

citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("state", "==", "CA").where("population", "<", 1000000)
Swift
citiesRef
    .whereField("state", isEqualTo: "CO")
    .whereField("name", isEqualTo: "Denver")
citiesRef
    .whereField("state", isEqualTo: "CA")
    .whereField("population", isLessThan: 1000000)
Objective-C
[[citiesRef queryWhereField:@"state" isEqualTo:@"CO"]
    queryWhereField:@"name" isGreaterThanOrEqualTo:@"Denver"];
[[citiesRef queryWhereField:@"state" isEqualTo:@"CA"]
    queryWhereField:@"population" isLessThan:@1000000];
  
Android
citiesRef.whereEqualTo("state", "CO").whereEqualTo("name", "Denver");
citiesRef.whereEqualTo("state", "CA").whereLessThan("population", 1000000);
자바
Query chainedQuery1 = cities.whereEqualTo("state", "CO")
    .whereEqualTo("name", "Denver");Query chainedQuery2 = cities.whereEqualTo("state", "CA")
    .whereLessThan("population", 1000000L);
Python
cities_ref = db.collection(u'cities')

sydney_query = cities_ref.where(
    u'state', u'==', u'CO').where(u'name', u'==', u'Denver')
large_us_cities_query = cities_ref.where(
    u'state', u'==', u'CA').where(u'population', u'>', 1000000)
Node.js
citiesRef.where('state', '==', 'CO').where('name', '==', 'Denver');citiesRef.where('state', '==', 'CA').where('population', '<', 1000000);
Go
denverQuery := cities.Where("name", "==", "Denver").Where("state", "==", "CO")
caliQuery := cities.Where("state", "==", "CA").Where("population", "<=", 1000000)query := cities.Where("country", "==", "USA").Where("population", ">", 5000000)
PHP
$chainedQuery = $citiesRef
    ->where('state', '=', 'CA')
    ->where('name', '=', 'San Francisco');
$chainedQuery = $citiesRef
    ->where('state', '=', 'CA')
    ->where('population', '<', 1000000);

또한 필드 1개에서만 범위 비교(<, <=, >, >=)를 실행할 수 있습니다.

올바른 방법: 필드 1개에서만 범위 필터 사용

citiesRef.where("state", ">=", "CA").where("state", "<=", "IN")
citiesRef.where("state", "==", "CA").where("population", ">", 1000000)
Swift
citiesRef
    .whereField("state", isGreaterThanOrEqualTo: "CA")
    .whereField("state", isLessThanOrEqualTo: "IN")
citiesRef
    .whereField("state", isEqualTo: "CA")
    .whereField("population", isGreaterThan: 1000000)
Objective-C
[[citiesRef queryWhereField:@"state" isGreaterThanOrEqualTo:@"CA"]
    queryWhereField:@"state" isLessThanOrEqualTo:@"IN"];
[[citiesRef queryWhereField:@"state" isEqualTo:@"CA"]
    queryWhereField:@"population" isGreaterThan:@1000000];
  
Android
citiesRef.whereGreaterThanOrEqualTo("state", "CA")
        .whereLessThanOrEqualTo("state", "IN");
citiesRef.whereEqualTo("state", "CA")
        .whereGreaterThan("population", 1000000);
자바
Query validQuery1 = cities.whereGreaterThanOrEqualTo("state", "CA")
    .whereLessThanOrEqualTo("state", "IN");
Query validQuery2 = cities.whereEqualTo("state", "CA")
    .whereGreaterThan("population", 1000000);
Python
cities_ref = db.collection(u'cities')
cities_ref.where(u'state', u'>=', u'CA').where(u'state', u'<=', u'IN')
Node.js
citiesRef.where('state', '>=', 'CA').where('state', '<=', 'IN');
citiesRef.where('state', '==', 'CA').where('population', '>', 1000000);
Go
stateQuery := cities.Where("state", ">=", "CA").Where("state", "<", "IN")
populationQuery := cities.Where("state", "==", "CA").Where("population", ">", 1000000)
PHP
$rangeQuery = $citiesRef
    ->where('state', '>=', 'CA')
    ->where('state', '<=', 'IN');

잘못된 방법: 서로 다른 필드에 범위 필터 사용

citiesRef.where("state", ">=", "CA").where("population", ">", 100000)
Swift
citiesRef
    .whereField("state", isGreaterThanOrEqualTo: "CA")
    .whereField("population", isGreaterThan: 1000000)
Objective-C
[[citiesRef queryWhereField:@"state" isGreaterThanOrEqualTo:@"CA"]
    queryWhereField:@"population" isGreaterThan:@1000000];
  
Android
citiesRef.whereGreaterThanOrEqualTo("state", "CA").whereGreaterThan("population", 100000);
자바
Query invalidRangeQuery = cities.whereGreaterThanOrEqualTo("state", "CA")
    .whereGreaterThan("population", 100000);
Python
cities_ref = db.collection(u'cities')
cities_ref.where(
    u'state', u'>=', u'CA').where(u'population', u'>=', 1000000)
Node.js
citiesRef.where('state', '>=', 'CA').where('population', '>', 1000000);
Go
query := cities.Where("state", ">=", "CA").Where("population", ">", 1000000)
PHP
$invalidRangeQuery = $citiesRef
    ->where('state', '>=', 'CA')
    ->where('population', '>', 1000000);

쿼리 제한사항

Cloud Firestore는 다음 유형의 쿼리를 지원하지 않습니다.

  • 이전 섹션에서 설명한 것과 같이 여러 필드에 범위 필터가 있는 쿼리
  • 여러 컬렉션 또는 하위 컬렉션의 단일 쿼리: 각 쿼리는 문서의 단일 컬렉션에서 실행됩니다. 데이터 구조가 쿼리에 어떤 영향을 미치는지 자세히 알아보려면 데이터 구조 선택을 참조하세요.
  • 개별 배열 멤버의 쿼리: 하지만 배열, 목록, 집합 다루기의 기술을 활용하여 배열과 유사한 데이터를 모델링하고 쿼리할 수 있습니다.
  • 논리적 OR 쿼리: 이 경우 각 OR 조건에 해당하는 별도의 쿼리를 만들고 앱에서 쿼리 결과를 병합해야 합니다.
  • != 절이 있는 쿼리: 이 경우 쿼리를 초과 및 미만 쿼리로 분할해야 합니다. 예를 들어 where("age", "!=", "30") 쿼리 절은 지원되지 않지만 where("age", "<", "30") 절이 있는 쿼리 하나와 where("age", ">", 30) 절이 있는 쿼리 하나, 이 2가지 쿼리를 결합하면 동일한 결과 세트를 얻을 수 있습니다.