Skip to content

Firestore에서_검색_쿼리_만들기

yujin45 edited this page Nov 25, 2024 · 1 revision

1️⃣ Firestore에서 startsWith를 구현하는 방법

Firestore는 기본적으로 startsWith와 같은 문자열 검색 기능을 직접 제공하지 않는다. 하지만 문자열의 범위를 설정하는 쿼리를 조합하여 유사한 동작을 구현할 수 있다.

💡 whereGreaterThanOrEqualTowhereLessThanOrEqualTo를 함께 사용하는 방법

Firestore는 문자열 비교를 사전순으로 처리하며, whereGreaterThanOrEqualTowhereLessThanOrEqualTo를 조합하여 특정 접두사로 시작하는 항목을 검색할 수 있다.

구현 방법

fireStore.collection("USER")
    .whereGreaterThanOrEqualTo("displayName", "Jo")
    .whereLessThanOrEqualTo("displayName", "Jo\\uf8ff")
    .get()
    .await()

작동 원리

  1. whereGreaterThanOrEqualTo("Jo"): displayName 필드가 "Jo"와 같거나 그보다 사전순으로 큰 값만 포함한다.
  2. whereLessThanOrEqualTo("Jo\\uf8ff"): displayName 필드가 "Jo"로 시작하는 값 중 가장 큰 범위까지만 포함한다.
  3. 위 두 조건을 조합하면 "Jo"로 시작하는 값(예: "Jo", "John", "Johnny")만 가져온다.

주의 사항

  • Firestore는 문자열 검색에서 대소문자를 구분하므로 "jo""Jo"는 다른 값으로 인식된다.
  • \\uf8ff는 유니코드 문자 중 가장 큰 값을 나타내며, 문자열 검색의 끝 범위를 설정할 때 사용된다.

❓ 왜 2가지를 함께 써줘야 할까?

1. whereGreaterThanOrEqualTo만 사용하는 경우

fireStore.collection("USER")
    .whereGreaterThanOrEqualTo("displayName", "Jo")
    .get()
    .await()

결과

  • 이 쿼리는 displayName이 "Jo"와 같거나 사전순으로 더 큰 값을 모두 가져옴
  • 즉, "Jo", "John", "Johnny", "Michael" 등이 포함

문제점

  • "Jo"로 시작하지 않는 "Michael", "Zoe"와 같은 값도 포함될 수 있음
  • 따라서 startsWith와 동일한 동작이 아니며, 범위를 좁히는 추가 조건이 필요

2. whereLessThanOrEqualTo만 사용하는 경우

fireStore.collection("USER")
    .whereLessThanOrEqualTo("displayName", "Jo\\uf8ff")
    .get()
    .await()

결과

  • 이 쿼리는 displayName"Jo\\uf8ff"보다 작거나 같은 모든 값을 가져옴
  • Firestore에서 문자열은 사전순으로 정렬되므로, "Jo"로 시작하는 항목만 포함. "Jo", "John", "Johnny"는 포함되지만, "Joker", "Michael" 등은 포함되지 않음.

문제점

  • 시작점을 지정하지 않았기 때문에 "Ja", "Jack"과 같은 "Jo"보다 작은 값도 포함될 수 있다.

3. 두 조건을 함께 사용할 때의 동작

fireStore.collection("USER")
    .whereGreaterThanOrEqualTo("displayName", "Jo")
    .whereLessThanOrEqualTo("displayName", "Jo\\uf8ff")
    .get()
    .await()

결과

  • 이 쿼리는 displayName이 "Jo"로 시작하는 항목만 정확히 검색.
  • "Jo", "John", "Johnny"는 포함
  • "Joker", "Michael", "Ja""Jo"로 시작하지 않는 값은 제외.

왜 필요한가?

  • whereGreaterThanOrEqualTo("Jo"): "Jo"와 같거나 더 큰 값부터 검색을 시작.
  • whereLessThanOrEqualTo("Jo\\uf8ff"): "Jo"로 시작하는 문자열 범위의 끝을 지정.
  • 두 조건이 함께 있어야 "Jo"로 시작하는 값만 정확히 포함.

4. 요약

조건 사용 동작 설명 결과
whereGreaterThanOrEqualTo만 사용 시작 범위만 지정, 끝 범위 없음 "Jo", "John", "Johnny", "Michael" 포함
whereLessThanOrEqualTo만 사용 끝 범위만 지정, 시작 범위 없음 "Ja", "Jack", "Jo", "John", "Johnny" 포함
둘 다 사용 시작과 끝 범위를 모두 지정하여 정확히 startsWith 흉내 냄 "Jo", "John", "Johnny"만 포함

결론

  • startsWith와 같은 동작 구현하려면 둘 다 필요.

2️⃣ 두 필드를 검색하는 방법 (OR 조건 구현)

Firestore는 기본적으로 OR 조건을 지원하지 않으므로, 두 개의 쿼리를 별도로 실행한 후 결과를 병합해야 한다.

구현 방법

suspend fun searchUsers(query: String): List<FirestoreUser> {
    val displayNameResults = fireStore.collection("USER")
        .whereGreaterThanOrEqualTo("displayName", query)
        .whereLessThanOrEqualTo("displayName", query + "\\uf8ff")
        .get()
        .await()
        .toObjects(FirestoreUser::class.java)
val emailResults = fireStore.collection(&quot;USER&quot;)
    .whereGreaterThanOrEqualTo(&quot;email&quot;, query)
    .whereLessThanOrEqualTo(&quot;email&quot;, query + &quot;\\uf8ff&quot;)
    .get()
    .await()
    .toObjects(FirestoreUser::class.java)

return (displayNameResults + emailResults).distinctBy { it.uid }

}

작동 원리

  1. displayName 필드와 email 필드 각각에 대해 검색 쿼리를 실행한다.
  2. 결과를 병합하고, 동일한 uid 값을 가진 중복 항목은 제거한다.
  3. 이를 통해 query로 시작하는 displayName 또는 email 필드를 검색할 수 있다.

주의 사항

  • 두 개의 쿼리가 실행되므로 네트워크 호출 비용이 늘어난다.
  • Firestore 쿼리는 항상 특정 필드에 대해 인덱싱이 필요하다.

결론

  • displayName과 email 둘 다 검색할 수 있게 하기 위해서는 위와 같은 방법을 사용할 수 있다.
  • 그러나 우선은 우리 기획은 email 기반 검색이기에 email 검색만 구현해보도록 하겠다.
Clone this wiki locally