[Firestore] 4편 - 쿼리에 해당하는 문서들 가져오기
https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0
저번 포스팅에 이어서 작성하였다.
드디어 Query 클래스에 대해 알아본다.
Query 클래스를 사용하여 컬렉션 하위의 쿼리에 해당하는 문서들을 한번에 가져올 수 있다.
테스트 목적으로만 Query 클래스를 상속하라고 제안하는듯 하다. 새 SDK 출시시 문제가 될 수 있다고 한다.
CollectionReference로 컬렉션 위치를 참조하여 super클래스인 Query클래스의 SQL을 모방한 메서드들을 사용하여 목적에 맞는 쿼리를 만들고(메서드 리턴 Query) 리턴된 Query의 get 메서드들을 통해 컬렉션 바로하위에 쿼리에 해당하는 문서들만 가져온다.
쿼리를 적용시켜 컬렉션 바로 하위에 포함된 여러 문서들 한번에 읽기
cities 컬렉션 바로 하위의 문서들에서 capital 필드가 Boolean true인 문서들만 가져온다.
whereEqualTo는 == 연산자에 해당되는데 밑에서 설명한다.
(콘솔 테스트 결과 더 하위의 문서들에는 적용되지 않고 바로 하위의 문서들만 검색이 가능했다)
documents <- QuerySnapshot 객체 이터레이블
document <- QueryDocumentSnapshot extends DocumentSnapshot
QueryDocumentSnapshot는 오버라이딩 메서드만 존재
파이어스토어 쿼리는 default로, 문서 id를 가지고 오름차순으로 쿼리와 맞는지 체크
(SQL ASC와 동일)
컬렉션 바로 하위의 모든 문서들 한번에 읽기
List subcollections of a document
안드로이드 클라이언트 라이브러리 지원하지 않는다.
Query 클래스로 쿼리 사용하기
https://firebase.google.com/docs/firestore/query-data/queries?authuser=0
쿼리 연산자
안드로이드의 경우 메서드에 오퍼레이터를 사용할 필요없이
비교 연산자에 해당하는 메서드가 메서드이름으로 명시되어 있다.
Query 클래스의 비교연산자에 해당하는 메서드들
메서드들을 사용할 때 null인 필드를 잘 확인 해야한다.
심플 쿼리 vs 복합 쿼리
심플 쿼리
==
각 쿼리 메서드마다 두가지 형태의 메서드가 존재하는데
위의 field명 String 대신 FieldPath인 필드 경로를 넣는 메서드도 존재한다.
샘플 데이터
테스트 1
정수 100인 필드가 존재하는 문서들만 뽑힌다.
테스트 2 - null타입 필드를 뽑을 수 있다.
!=
whereNotEqualTo("field", 100) 의 경우
일단 field 필드가 존재하는 문서들만 뽑힐 수 있다.
field 필드가 존재하는데, 정수형 100이 아닌 문서들은 모두 뽑힌다
1. 메서드에 존재하는 값으로 설정하면 null 타입필드를 가진 문서는 뽑히지 않는다.
2. 메서드에 null값을 사용하면 null필드를 제외한 필드가 존재하는 모든 문서가 뽑힌다.
테스트 1 - 존재하는 값을 메서드의 인자에 설정시 null필드를 가진 문서가 채택되는지 확인
다른 타입에 해당하는 문서는 뽑혀나왔지만
null필드에 해당하는 문서는 뽑혀나오지 않음을 확인 가능
빈 문서 또한 필드가 존재하지 않으므로 뽑혀나오지 않음
테스트2 - null값을 whereNotEqualTo 의 인자에 사용
null필드가 아닌 필드가 존재하는 모든 문서가 뽑힌다.
document1, document2, document3 이 뽑힌다. (로그는 콘솔을 수정해버려서 남기지 못했다)
참고 - null인 필드 테스트
문서에서 get(필드명:String)을 사용할 때 없는 필드도 null이 뽑히기 때문에
null필드의 존재유무 확인은 contains(필드명)으로 확인할 수 있다.
존재하지 않는 필드의 경우 contains("없는필드명")은 false 리턴할 것이다.
배열 타입 필드에 해당하는 값의 요소가 존재하는지 확인
배열 타입인 필드에 element들중 value값이 존재하는지 확인
존재하면 문서가 뽑힌다.
필드 타입이 배열인 경우에 사용한다.
배열 타입인 필드에 element들중 제공된 리스트 값들중 하나라도 존재하면 문서가 뽑힌다.
메서드는 항상 배열 타입 필드만 필터링한다.
배열을 제외한 다른 타입의 필드에 메서드를 사용하면 아무일도 일어나지 않는다(문서 안뽑힘)
in operator
whereArrayContainsAny가 배열인 필드중 제공된 값중 하나라도 존재하면 문서를 뽑아냈다면
whereIn은 배열을 제외한 다른 타입의 필드 버전이라고 보면된다.
(배열 타입 필드도 먹히나 확인해본 결과 적용되지 않았다)
whereNotEqualTo, whereEqualTo 가 필드의 하나의 값과 비교하지만
whereIn, whereNotIn의 경우 비교 대상의 값 개수를 최대 10개를 지정할 수 있다.
최대 10개로 제한된다. OR이다. 제공된 값중 하나라도 만족하면 문서가 뽑힌다.
테스트 1 - 기본동작
null매칭 불가능 메서드라 null값을 넣어도 매칭 작업을 할 수 없다( null필드 문서 안뽑힘)
테스트 2 - 각 비교값을 배열로 설정할 수 있다.
whereIn(필드명, 리스트( 리스트1, 리스트2 ) -> 필드값 in 리스트1, 리스트2
-> 쿼리조건 : 필드값이 리스트1과 완전일치(순서,값,길이) or 리스트2와 완전일치
document2는 순서가 다르고 , document3는 길이가 다르다, document4는 값이 다르다.
not - in operator
AND이다. in연산자인 whereIn메서드와 같이 최대 10개 제공가능
제공된 값중 하나라도 만족하면 안된다.
(1,2,3) -> 1,2,3 모두 아닌 문서만 리턴
(1,2,3,4) -> 1,2,3,4 모두 아닌 문서만 리턴
null필드 매칭을 할 수 없어서, null매칭시에는 whereNotEqualTo를 사용하라고 하고 있다.
(whereNotEqualTo 예시 테스트2에서 null필드를 인자로 넣었을 때 null매칭이 가능해서
null필드가 아닌 필드 값이 존재하는 모든 문서가 뽑혔다)
테스트1 - 존재하는 값을 메서드 인자로 설정시
whereNotEqualTo 와 동일하게 null타입을 가진 문서는 뽑히지 않는다.
테스트 2 - 메서드의 인자에 null 값
whereNotIn메서드는 null을 비교할 수 없어 whereNotEqualTo를 사용하라고 하고 있다.
null을 넣었더니 비교를 하지 못해 아무것도 뽑히지 않았다.
(위의 테스트를 보면 whereNotEqualTo의 경우 null필드 매칭이 가능했었다)
테스트3 - 메서드 사용 본 목적
whereIn, whereNotIn, whereArrayContainsAny의 인자 리스트의 최대 길이 10
whereArrayContains 와 whereArrayContainsAny 둘 중 하나만 사용가능
whereIn, whereNotIn, whereArrayContainsAny 셋 중 하나만 사용가능
whereNotIn, whereNotEqualTo 둘 중 하나만 사용가능
whereEqualTo와 whereIn의 쿼리 순서를 정렬할 수 없다 (바로 밑에서 공부할 내용인 복합 쿼리에 대한 내용인것 같다. )
복합 쿼리
이전까지 설명했던 내용들은 단일 필드에 대한 쿼리였지만 , 여러 필드에 대한 쿼리인 복합 쿼리를 사용할 수 있다.
색인 관련
동일성 연산자인 (==. whereEqualTo 또는 array-contains. whereArrayContains) 는 여러개 체이닝 가능하다.
그러나 동일성 연산자(==, array-contains) 와 비동일성 연산자(<, <=, >=, >, !=)를 결합한 복합 쿼리를 사용하기 위해서는 복합 인덱스(색인)를 must 생성해줘야 한다.
색인 등록이 필요한 쿼리의 경우 색인 등록을 하지 않은 상태로 쿼리를 날리면 Task의 addOnFailureListener에 해당하는 메서드가 호출된다)
citiesRef.whereEqualTo("state", "CO").whereEqualTo("name", "Denver") //색인 생성 필요x
citiesRef.whereEqualTo("state", "CA").whereLessThan("population", 1000000) //색인 생성 필요o
메서드 제한 관련 (여러 필드 복합 쿼리, 단일 필드 복합 쿼리)
복합 쿼리에 array-contains, array-contains-any 둘중 하나만 가능.
whereGreaterThan, whereGreaterThanOrEqualTo, whereLessThan, whereLessThanOrEqualTo, whereNotEqualTo 는 하나의 필드에 몰빵하지 않으면 쿼리 실패됨
범위 비교, != 중에 범위 비교메서드가 두개의 필드에 적용되어 쿼리 실패
다음 포스팅인 5편에서 Firestore 색인에 대해 공부하고
색인 생성이 필요한 복합 쿼리를 테스트해보려 한다.
바로 밑의 컬렉션 그룹 쿼리 또한 색인 생성이 필요하다. 컬렉션 그룹 쿼리는 색인 생성 외에 룰까지 설정해야 한다.
컬렉션 그룹 쿼리
이전까지는 하나의 컬렉션에서 쿼리하는 법에 대해 알아보았다
컬렉션 그룹 쿼리란 동일한 이름(id)를 가진 컬렉션들에 대해 쿼리가 적용되는 것이다.
동일한 이름을 가진 컬렉션들 여러개를 한번에 쿼리하여 쿼리조건에 맞는 문서들을 가져올 수 있다.
FirebaseFirestore 클래스의 메서드를 통해 컬렉션 그룹 쿼리에 해당하는 Query 객체를 참조하여 이전처럼 사용하면된다.
참고- 컬렉션, 문서 이름 중복
문서 바로 하위에만 동일한 이름의 컬렉션 생성 불가. 이외에 이름 중복 가능
컬렉션 바로 하위에만 동일한 이름의 문서 생성 불가. 이외에 이름 중복 가능
전자, 후자 모두 가능
전자
collection - document - collection2 - document2 - 가격: 8000
- document3 - collection2 - document4 - 가격: 6000
후자
collection- document - collection2 - document2 - price: 8000
collection2 - document3 - price: 6000
컬렉션 그룹 쿼리를 사용하기 전에 컬렉션 그룹 쿼리를 지원하기 위해 인덱스를 생성해야 한다.
(다음 편 포스팅에서 색인에 대한 내용을 정리)
웹, 모바일의 경우 인덱스 이외에 컬렉션 그룹을 쿼리 요청에 대한 룰을 허용시켜야 한다.
참조 링크
테스트 - 데이터 구조
group - document1 - 데이터fieldTest : 100
- document2 - group - document3 - 데이터fieldTest : 300
- document4 - group - document5 - 데이터fieldTest : 500
컬렉션 그룹 쿼리를 위한 컬렉션 그룹 스코프 단일필드 색인 생성
whereIn 메서드만 사용할 것이라 오름차순,내림차순 중 하나만 선택했다.
컬렉션 그룹 스코프 생성시 컬렉션 스코프 색인까지 같이 생성되는 듯 하다.
색인 생성 완료후 코드를 실행하면
Firestore 쿼리 제한 요약
https://firebase.google.com/docs/firestore/query-data/order-limit-data?authuser=0
ORDERBY, LIMIT 은 간단해서 정리할게 별로 없다.
사용되는 Qeury 클래스 메서드
- 정렬
orderBy(필드명), orderBy(필드명, Query.Direction.ASCENDING)
SQL orderby처럼 state필드로 먼저 정렬되고, population필드로 정렬된다.
- 제한
limit(3) 최대 문서 세개 뽑음
limitToLast(3) 마지막 부분의 세개
where, orderby, limit 다 사용하여 SQL 비슷하게 따라 쓸 수 있다.
orderBy메서드 사용시 주의점
orderBy메서드는 정렬기능이지만 필드 존재 필터링이된다. 필드 존재하지 않는 것 안뽑힘.
where메서드로 필터링했는데 어떤 문서는 orderBy에 해당하는 필드가 존재할 수도있고 안할수도 있는 것을 생각하면 정렬이 불가능하기 때문에 자연스럽게 이해가 된다.
필드 존재 안하는 문서 안뽑힘
범위 비교 연산자 사용시 첫 orderBy는 범위 비교 연산자 메서드 필드와 같아야함
==,in 메서드가 설정된 필드로는, orderby 메서드 사용불가