Google Firestore : 속성 값의 하위 문자열에 대한 쿼리 (텍스트 검색)


103

간단한 검색 필드를 추가하고 싶습니다. 다음과 같은 것을 사용하고 싶습니다.

collectionRef.where('name', 'contains', 'searchTerm')

을 사용해 보았지만 where('name', '==', '%searchTerm%')아무것도 반환하지 않았습니다.


2
plesase는 어떤 해결책을 찾았습니다. 나는 부족함없이 비슷한 무언가를 위해 일을
찾고 있었다

1
이제 Firebase가이를 지원합니다. 제발 업데이트 답 : stackoverflow.com/a/52715590/2057171
알버트 렌쇼

1
가장 좋은 방법은 각 문서를 수동으로 인덱싱하는 스크립트를 만드는 것입니다. 그런 다음 해당 인덱스를 쿼리합니다. 이것을 확인하십시오 : angularfirebase.com/lessons/…
Kiblawi_Rabee

답변:


34

그런 운영자가 없다, 허용 사람은 ==, <, <=, >, >=.

당신은 사이의 시작이 그 모든 것을 예를 들어, 단지 접두사에 의해 필터링 할 수 있습니다 barfoo사용할 수있는

collectionRef.where('name', '>=', 'bar').where('name', '<=', 'foo')

이를 위해 Algolia 또는 ElasticSearch 와 같은 외부 서비스를 사용할 수 있습니다 .


5
그것은 내가 찾고있는 것이 아닙니다. 긴 제목을 가진 많은 제품 목록이 있습니다. "Rebok Mens 테니스 라켓". 사용자는을 검색 할 수 tennis있지만 사용 가능한 쿼리 연산자를 기반으로 해당 결과를 얻을 수있는 방법이 없습니다. 결합 >=하고 <=작동하지 않습니다. ... 물론 나는 Algolia를 사용할 수 있지만, 나는 또한 단지 경우 FireStore로 전환해야 대부분의 질의가 아니라 할 중포 기지와 함께 사용할 수
tehfailsafe

4
@tehfailsafe 글쎄요 당신의 질문은 '필드에 문자열이 포함되어 있는지 쿼리하는 방법'이며 응답은 '할 수 없습니다'입니다.
Kuba

20
@ A.Chakroun 내 대답에서 정확히 무례한 것은 무엇입니까?
Kuba

18
tbh 이것은 정말로 필요한 것입니다. Firebase 팀이 왜 이에 대해 생각하지 않았는지 이해할 수 없습니다
Dani

2
Firebase가 쿼리에 너무 약하다는 것은 정말 놀랍습니다. 그렇게 간단한 쿼리를 지원할 수 없다면 너무 많은 사람들이 그것을 사용하고 있다는 것을 믿을 수 없습니다.
Bagusflyer

43

제한이 진행되는 한 Kuba의 대답은 사실이지만 세트와 같은 구조로 부분적으로 에뮬레이션 할 수 있습니다.

{
  'terms': {
    'reebok': true,
    'mens': true,
    'tennis': true,
    'racket': true
  }
}

이제 다음으로 쿼리 할 수 ​​있습니다.

collectionRef.where('terms.tennis', '==', true)

이는 Firestore가 모든 필드에 대해 자동으로 색인을 생성하기 때문에 작동합니다. 불행히도 Firestore는 복합 색인을 자동으로 생성하지 않기 때문에 복합 쿼리에 대해 직접 작동하지 않습니다.

단어 조합을 저장하여이 문제를 해결할 수 있지만 속도가 너무 빠릅니다.

여전히 아웃 보드 전체 텍스트 검색을 사용하는 것이 좋습니다 .


클라우드 기능을 사용할 수 있습니까? cloud.google.com/appengine/docs/standard/java/search에서 있습니까?
헨리

1
이 답변에 대한 후속 조치로 이것을 요청하는 경우 AppEngine의 전체 텍스트 검색은 Firestore와 완전히 분리되어 있으므로 직접적으로 도움이되지는 않습니다. 클라우드 기능을 사용하여 데이터를 복제 할 수 있지만 본질적으로 아웃 보드 전체 텍스트 검색을 사용하는 것이 좋습니다. 다른 질문이 있으면 새 질문을 시작하세요.
길 길버트

1
Firestore에서는 사용하기 전에 모든 용어를 색인화해야합니다where
Husam

4
Husam이 언급했듯이 이러한 모든 필드는 인덱싱되어야합니다. 내 제품 이름에 포함 된 모든 용어를 검색 할 수 있기를 원했습니다. 그래서 나는 어디에 ( 'nameSegments.tennis', '==', true)가 검색되기를 바라고, 각각에 할당 된 'true'값을 가진 키가 제품 이름의 일부인 'object'유형 속성을 문서에 만들었습니다. 작동하지만 firestore는 다른 모든 용어에 대해 동일한 nameSegments.tennis에 대한 색인 생성을 제안합니다. 무한한 수의 용어가있을 수 있기 때문에이 답변은 모든 검색어가 미리 정의 된 매우 제한된 시나리오에서만 사용할 수 있습니다.
Slawoj

2
@epeleg 쿼리는 인덱스를 만든 후에 작동하지만 제품 이름에 포함 된 가능한 각 용어에 대한 인덱스를 만드는 것은 불가능하므로 제품 이름의 용어에 대한 텍스트 검색의 경우이 방법이 제 경우에는 작동하지 않았습니다.
Slawoj

43

@Kuba의 답변에 동의하지만 접두사 검색에 완벽하게 작동하려면 작은 변경 사항을 추가해야합니다. 여기 나를 위해 일한 것

이름으로 시작하는 레코드 검색 queryText

collectionRef.where('name', '>=', queryText).where('name', '<=', queryText+ '\uf8ff').

\uf8ff쿼리에 사용 된 문자 는 유니 코드 범위에서 매우 높은 코드 포인트입니다 (PUA (Private Usage Area) 코드). 유니 코드에서 대부분의 일반 문자 뒤에 있기 때문에 쿼리는로 시작하는 모든 값과 일치합니다 queryText.


1
좋은 대답!, 이것은 접두사 텍스트 검색에 적합합니다. 텍스트에서 단어를 검색하려면이 게시물에 설명 된대로 "array-contains"구현을 시도해보십시오. medium.com/@ken11zer01/…
guillefd

생각 만해도 이론적으로는 다른 필드를 만들고 데이터를 반전하여 queryTest 로 끝나는 모든 값을 일치시킬 수 있습니다.
Jonathan

예 @Jonathan, 그것도 가능합니다.
Ankit Prajapati

30

Firebase는 문자열 내에서 용어 검색을 명시 적으로 지원하지 않지만

Firebase는 (현재) 귀하의 사례와 다른 많은 문제를 해결할 다음을 지원합니다.

2018 년 8 월부터 array-contains쿼리 를 지원 합니다. 참조 : https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html

이제 모든 주요 용어를 필드로 배열에 설정 한 다음 'X'가 포함 된 배열이있는 모든 문서를 쿼리 할 수 ​​있습니다. 논리 AND를 사용하여 추가 쿼리에 대한 추가 비교를 수행 할 수 있습니다. (Firebase 는 현재 여러 배열 포함 쿼리에 대한 복합 쿼리를 기본적으로 지원하지 않기 때문입니다. 'AND'정렬 쿼리는 클라이언트 측에서 수행해야합니다.)

이 스타일로 배열을 사용하면 동시 쓰기에 최적화 될 수 있습니다. 일괄 요청을 지원하는지 테스트하지 않았지만 (문서는 말하지 않음) 공식 솔루션이기 때문에 그렇게 할 것입니다.


용법:

collection("collectionPath").
    where("searchTermsArray", "array-contains", "term").get()

12
이것은 좋은 해결책입니다. 그러나 내가 틀렸다면 저를 정정하십시오.하지만 @tehfailsafe가 요청한 것을 할 수 없다고 생각합니다. 예를 들어 문자열 "abc"를 포함하는 모든 이름을 얻으려는 경우 정확한 이름이 "abc"인 문서 만 반환하고 "abcD"또는 "abcD"또는 "0abc"가 나옵니다.
Yulian

1
@Yulian 프로그래밍 세계에서 Search term일반적으로 양쪽에서 공백, 구두점 등으로 구분 된 전체 용어를 의미하는 것으로 이해됩니다. 당신이 구글 경우 abcde지금 당신은 단지 같은 것들에 대한 결과를 찾을 수 %20abcde.또는 ,abcde!아니지만을 abcdefghijk... 도 확실히 전체 알파벳 입력 된 훨씬 더 일반적인 것은 인터넷에서 찾을 수있다하지만, 검색은 고립 된 ABCDE위한거야 * ABCDE위한 것이 아닙니다
알버트 렌쇼

1
나는 당신의 요점을 보았고 그것에 동의하지만 아마도 'contains'나는 많은 프로그래밍 언어에서 내가 말하는 것을 정확히 의미 하는 단어로 오도했을 것입니다 . '%searchTerm%'SQL 관점에서도 마찬가지 입니다.
Yulian

2
@Yulian 네, 알겠습니다. Firebase는 NoSQL이므로 와일드 카드 문자열 검색과 같은 일부 범위를 벗어난 문제로 인해 제한 될 수 있지만 이러한 유형의 작업을 빠르고 효율적으로 만드는 데 정말 좋습니다.
Albert Renshaw

2
글쎄, 문서를 업데이트 할 때마다 titleArray : [ 'this', 'is', 'a', 'title']과 같이 분할 된 단어의 표현을 사용하여 각각에 대해 별도의 필드를 만들 수 있습니다. 그런 다음 검색은 제목 대신 해당 필드를 기반으로합니다. 이 필드를 생성하려면 triiger onUpdate를 콜드 생성합니다. 검색 기반 텍스트에 대한 많은 작업이 있지만 NoSQL의 성능이 향상되었습니다.
sfratini

14

경우 FireStore 워드 프로세서 , 클라우드 경우 FireStore은 기본 인덱싱을 지원하지 않거나 문서에서 텍스트 필드를 검색합니다. 또한 클라이언트 측에서 필드를 검색하기 위해 전체 컬렉션을 다운로드하는 것은 실용적이지 않습니다.

AlgoliaElastic Search 와 같은 타사 검색 솔루션 이 권장됩니다.


46
이상적이지는 않지만 문서를 읽었습니다. 단점은 Algolia와 Firestore의 가격 책정 모델이 다르다는 것입니다. 하루에 너무 많이 쿼리하지 않는 한 Firestore에 600,000 개의 문서를 저장할 수 있습니다. 검색을 위해 Algolia로 푸시하면 이제 Firestore 문서에서 제목 검색을 수행하기 위해 Algolia에 매월 310 달러를 지불해야합니다.
tehfailsafe

2
문제는이 무료로되지 않는 것입니다
대니

이것은 제기 된 질문에 대한 정답이며 최고로 받아 들여 져야합니다.
briznad

11

여기에 몇 가지 참고 사항 :

1.) \uf8ff 다음과 같은 방식으로 작동합니다.~

2.) where 절 또는 start end 절을 사용할 수 있습니다.

ref.orderBy('title').startAt(term).endAt(term + '~');

정확히 동일

ref.where('title', '>=', term).where('title', '<=', term + '~');

3) 당신이 반대하면 아니, 그것은 작동하지 않습니다 startAt()endAt()모든 조합에서, 그러나, 당신이 반전되는 제 2 검색 필드를 생성하고, 그 결과를 조합하여 동일한 결과를 얻을 수 있습니다.

예 : 먼저 필드를 만들 때 필드의 반전 된 버전을 저장해야합니다. 이 같은:

// collection
const postRef = db.collection('posts')

async function searchTitle(term) {

  // reverse term
  const termR = term.split("").reverse().join("");

  // define queries
  const titles = postRef.orderBy('title').startAt(term).endAt(term + '~').get();
  const titlesR = postRef.orderBy('titleRev').startAt(termR).endAt(termR + '~').get();

  // get queries
  const [titleSnap, titlesRSnap] = await Promise.all([
    titles,
    titlesR
  ]);
  return (titleSnap.docs).concat(titlesRSnap.docs);
}

이것으로, 당신은 마지막을 검색 할 수 있습니다 임의의 중간 문자 나 문자 그룹이 아닌 문자열 필드 문자와 첫 번째 문자를 . 이것은 원하는 결과에 더 가깝습니다. 그러나 이것은 우리가 임의의 중간 문자 나 단어를 원할 때 실제로 도움이되지 않습니다. 또한 모든 것을 소문자로 저장하거나 검색을 위해 소문자 사본을 저장해야하므로 대소 문자가 문제가되지 않습니다.

4.) 단어가 몇 개 밖에없는 경우 Ken Tan의 방법 은 원하는 모든 것을 수행하거나 최소한 약간 수정 한 후에 수행합니다. 그러나 텍스트 단락만으로도 1MB 이상의 데이터를 기하 급수적으로 생성 할 수 있으며 이는 firestore의 문서 크기 제한보다 큽니다 (알고 있습니다. 테스트했습니다).

5.) 배열 포함을 결합 할 수있는 경우 (또는 배열의 일부 형태)을 \uf8ff트릭 과 한계에 도달하지 않는 실행 가능한 검색이있을 수 있습니다. 나는지도와 함께 모든 조합을 시도했고, 가도 안된다. 누구나 이것을 알아 내고 여기에 게시하십시오.

6.) ALGOLIA 및 ELASTIC SEARCH에서 벗어나야하고 내가 당신을 탓하지 않는다면 Google Cloud에서 항상 mySQL, postSQL 또는 neo4J를 사용할 수 있습니다. 세 가지 모두 설정이 쉬우 며 프리 티어가 있습니다. 데이터를 저장하는 클라우드 함수 onCreate ()와 데이터 검색을위한 onCall () 함수가 있습니다. 단순하다 ... 그렇다면 mySQL로 전환하지 않는 이유는 무엇입니까? 물론 실시간 데이터! 누군가 가 실시간 데이터를 위해 websocks 로 DGraph를 작성하면 저를 세어보세요!

Algolia와 ElasticSearch는 검색 전용 db로 구축되었으므로 빠르지는 않지만 비용을 지불하면됩니다. Google, 왜 우리를 Google에서 멀어지게하고 MongoDB noSQL을 따르고 검색을 허용하지 않습니까?

업데이트-솔루션을 만들었습니다.

https://fireblog.io/blog/post/firestore-full-text-search


훌륭한 개요와 매우 도움이됩니다.
RedFilter

대박! 잘 구조화되고 유익한 응답을 위해 찬성합니다.
King Of The Jungle

10

늦은 답변이지만 여전히 답변을 찾고있는 모든 사용자를 위해 사용자 컬렉션이 있고 컬렉션의 각 문서에 "username"필드가 있으므로 사용자 이름이 "al"로 시작하는 문서를 찾고 싶다면 우리는 다음과 같이 할 수 있습니다

 FirebaseFirestore.getInstance().collection("users").whereGreaterThanOrEqualTo("username", "al")

이것은 훌륭한 쉬운 해결책입니다. 감사합니다. 그러나 두 개 이상의 필드를 확인하려면 어떻게해야합니까? OR로 연결된 "이름"과 "설명"처럼?
시도해보십시오

두 필드를 기반으로 쿼리 할 수 ​​없다고 생각합니다. 슬프게도
파이어베이스

1
확인 됨, @MoTahir. Firestore에는 "OR"이 없습니다.
Rap

해당 솔루션이 "al"로 시작하는 사용자 이름과 일치하지 않습니다. 예를 들어 "hello"는 일치합니다 ( "hello"> "al")
antoine129

OR로 쿼리하는 것은 단순히 두 개의 검색 결과를 결합하는 문제입니다. 결과를 정렬하는 것은 다른 문제입니다 ...
Jonathan

7

Firebase가 곧 문자열에 색인 [i] startAt을 캡처하기 위해 "string-contains"와 함께 나올 것이라고 확신합니다.하지만 웹을 조사한 결과 다른 사람이 다음과 같은 데이터를 설정 한이 솔루션을 발견했습니다. 이

state = {title:"Knitting"}
...
const c = this.state.title.toLowerCase()

var array = [];
for (let i = 1; i < c.length + 1; i++) {
 array.push(c.substring(0, i));
}

firebase
.firestore()
.collection("clubs")
.doc(documentId)
.update({
 title: this.state.title,
 titleAsArray: array
})

여기에 이미지 설명 입력

이와 같은 쿼리

firebase
.firestore()
.collection("clubs")
.where(
 "titleAsArray",
 "array-contains",
 this.state.userQuery.toLowerCase()
)

전혀 권장하지 않습니다. 문서에는 2 만 줄 제한이 있으므로 문서가 이러한 제한에 도달하지 않을 때까지 이러한 방식으로 사용할 수 없습니다
Sandeep

현재로서는 최선의 선택입니다. 그 밖의 권장 사항은 무엇입니까?
Nick Carducci

1
@Sandeep 나는 크기가 문서 당 1MB 크기와 20 수준의 깊이로 제한되어 있다고 확신합니다. 20k 라인이란 무엇을 의미합니까? Algolia 또는 ElasticSearch를 사용할 수없는 경우 현재 가장 좋은 해결 방법입니다.
ppicom

5

Algolia와 같은 타사 서비스를 사용하고 싶지 않다면 Firebase Cloud Functions 가 훌륭한 대안입니다. 입력 매개 변수를 수신하고 서버 측 레코드를 처리 한 다음 기준과 일치하는 항목을 반환 할 수있는 함수를 만들 수 있습니다.


1
안드로이드는 어떻습니까?
Pratik Butani

사람들이 컬렉션의 모든 단일 레코드를 반복하도록 제안하고 있습니까?
DarkNeuron

별로. .every (), .some (), .map (), .filter () 등과 같은 Array.prototype. *를 사용합니다. 이것은 Firebase 함수의 서버에있는 Node에서 값을 반환하기 전에 수행됩니다. 고객.

3
검색하려면 모든 문서를 읽어야하므로 비용이 발생하고 시간이 많이 걸립니다.
Jonathan

3

실제로 Firestore 내에서이 작업을 수행하는 가장 좋은 솔루션은 모든 하위 문자열을 배열에 넣고 array_contains 쿼리를 수행하는 것입니다. 이를 통해 하위 문자열 일치를 수행 할 수 있습니다. 모든 하위 문자열을 저장하는 것은 약간 과도하지만 검색어가 짧으면 매우 합리적입니다.


2

나는 방금이 문제가 있었고 매우 간단한 해결책을 찾았습니다.

String search = "ca";
Firestore.instance.collection("categories").orderBy("name").where("name",isGreaterThanOrEqualTo: search).where("name",isLessThanOrEqualTo: search+"z")

isGreaterThanOrEqualTo를 사용하면 검색 시작 부분을 필터링하고 isLessThanOrEqualTo 끝에 "z"를 추가하여 다음 문서로 롤오버되지 않도록 검색을 제한합니다.


3
이 솔루션을 시도했지만 전체 문자열을 입력했을 때만 작동합니다. 예를 들어, "무료"라는 용어를 얻으려면 "fr"을 입력하기 시작하면 아무 것도 반환되지 않습니다. "무료"를 입력하면 해당 용어가 스냅 샷을 제공합니다.
Chris

동일한 코드 형식을 사용하고 있습니까? 그리고 용어는 firestore의 문자열입니까? documentId로 필터링 할 수 없다는 것을 알고 있습니다.
Jacob Bonk

2

선택한 답변은 정확한 검색에만 적용되며 자연스러운 사용자 검색 동작이 아닙니다 ( "Joe ate an apple today"에서 "apple"검색은 작동하지 않음).

위의 Dan Fein의 대답은 더 높은 순위가되어야한다고 생각합니다. 검색중인 문자열 데이터가 짧은 경우 문서의 배열에 문자열의 모든 하위 문자열을 저장 한 다음 Firebase의 array_contains 쿼리를 사용하여 배열을 검색 할 수 있습니다. Firebase 문서는 1MiB (1,048,576 바이트)로 제한됩니다 ( Firebase 할당량 및 한도 )로 되며 문서에 약 1 백만 문자가 저장됩니다 (1 문자 ~ = 1 바이트라고 생각합니다). 문서가 1 백만 마크에 가까워지지 않는 한 부분 문자열을 저장하는 것이 좋습니다.

사용자 이름을 검색하는 예 :

1 단계 : 프로젝트에 다음 문자열 확장을 추가합니다. 이렇게하면 문자열을 하위 문자열로 쉽게 나눌 수 있습니다. ( 여기에서 찾았습니다 ).

extension String {

var length: Int {
    return count
}

subscript (i: Int) -> String {
    return self[i ..< i + 1]
}

func substring(fromIndex: Int) -> String {
    return self[min(fromIndex, length) ..< length]
}

func substring(toIndex: Int) -> String {
    return self[0 ..< max(0, toIndex)]
}

subscript (r: Range<Int>) -> String {
    let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                        upper: min(length, max(0, r.upperBound))))
    let start = index(startIndex, offsetBy: range.lowerBound)
    let end = index(start, offsetBy: range.upperBound - range.lowerBound)
    return String(self[start ..< end])
}

2 단계 : 사용자 이름을 저장할 때이 함수의 결과도 동일한 문서에 배열로 저장합니다. 이렇게하면 원본 텍스트의 모든 변형이 만들어져 배열에 저장됩니다. 예를 들어 텍스트 입력 "Apple"은 다음 배열을 생성합니다. [ "a", "p", "p", "l", "e", "ap", "pp", "pl", "le ","app ","ppl ","ple ","appl ","pple ","apple "], 사용자가 입력 할 수있는 모든 검색 기준을 포함해야합니다. 모든 결과를 원하면 maximumStringSize를 nil로 둘 수 있지만 긴 텍스트가있는 경우 문서 크기가 너무 커지기 전에 제한하는 것이 좋습니다. 약 15 개 정도가 저에게 잘 작동합니다 (대부분의 사람들은 긴 구문을 검색하지 않습니다. ).

func createSubstringArray(forText text: String, maximumStringSize: Int?) -> [String] {

    var substringArray = [String]()
    var characterCounter = 1
    let textLowercased = text.lowercased()

    let characterCount = text.count
    for _ in 0...characterCount {
        for x in 0...characterCount {
            let lastCharacter = x + characterCounter
            if lastCharacter <= characterCount {
                let substring = textLowercased[x..<lastCharacter]
                substringArray.append(substring)
            }
        }
        characterCounter += 1

        if let max = maximumStringSize, characterCounter > max {
            break
        }
    }

    print(substringArray)
    return substringArray
}

3 단계 : Firebase의 array_contains 함수를 사용할 수 있습니다!

[yourDatabasePath].whereField([savedSubstringArray], arrayContains: searchText).getDocuments....

0

Firestore를 사용하면 전체 텍스트 검색을 구현할 수 있지만 그렇지 않은 경우보다 읽기 비용이 더 많이 들고 특정 방식으로 데이터를 입력하고 색인을 생성해야합니다. 따라서이 접근 방식에서는 Firebase 클라우드 기능을 사용하여 다음을 수행 할 수 있습니다. 다음 h(x)을 충족 하는 선형 해시 함수 를 선택하면서 입력 텍스트를 토큰 화 한 다음 해시합니다 x < y < z then h(x) < h (y) < h(z). 토큰 화의 경우 문장에서 불필요한 단어를 제거 할 수있는 함수의 콜드 시작 시간을 낮게 유지하기 위해 경량 NLP 라이브러리를 선택할 수 있습니다. 그런 다음 Firestore에서보다 작거나 큰 연산자를 사용하여 쿼리를 실행할 수 있습니다. 데이터도 저장하는 동안 텍스트를 저장하기 전에 해시해야하며 일반 텍스트를 변경하는 것처럼 해시 된 값도 변경되는 것처럼 일반 텍스트도 저장해야합니다.


0

이것은 나를 위해 완벽하게 작동했지만 성능 문제가 발생할 수 있습니다.

Firestore를 쿼리 할 때 다음을 수행하십시오.

   Future<QuerySnapshot> searchResults = collectionRef
        .where('property', isGreaterThanOrEqualTo: searchQuery.toUpperCase())
        .getDocuments();

FutureBuilder에서 다음을 수행하십시오.

    return FutureBuilder(
          future: searchResults,
          builder: (context, snapshot) {           
            List<Model> searchResults = [];
            snapshot.data.documents.forEach((doc) {
              Model model = Model.fromDocumet(doc);
              if (searchQuery.isNotEmpty &&
                  !model.property.toLowerCase().contains(searchQuery.toLowerCase())) {
                return;
              }

              searchResults.add(model);
            })
   };

0

오늘 현재, 기본적으로 전문가가 질문에 대한 답변으로 제안한 3 가지 해결 방법이 있습니다.

나는 그들 모두를 시도했다. 나는 그들 각각에 대한 나의 경험을 문서화하는 것이 유용 할 것이라고 생각했습니다.

방법 -A : 사용 : (dbField "> ="searchString) & (dbField "<="searchString + "\ uf8ff")

@Kuba 및 @Ankit Prajapati가 제안 함

.where("dbField1", ">=", searchString)
.where("dbField1", "<=", searchString + "\uf8ff");

A.1 Firestore 쿼리는 단일 필드에서 범위 필터 (>, <,> =, <=) 만 수행 할 수 있습니다. 여러 필드에 범위 필터가있는 쿼리는 지원되지 않습니다. 이 방법을 사용하면 db의 다른 필드 (예 : 날짜 필드)에 범위 연산자를 사용할 수 없습니다.

A.2. 이 방법은 동시에 여러 필드에서 검색하는 데는 작동하지 않습니다. 예를 들어 검색 문자열이 필드 (이름, 메모 및 주소)에 있는지 확인할 수 없습니다.

방법 -B : 맵의 각 항목에 대해 "true"인 검색 문자열의 MAP 사용 및 쿼리에서 "=="연산자 사용

@Gil Gilbert가 제안 함

document1 = {
  'searchKeywordsMap': {
    'Jam': true,
    'Butter': true,
    'Muhamed': true,
    'Green District': true,
    'Muhamed, Green District': true,
  }
}

.where(`searchKeywordsMap.${searchString}`, "==", true);

B.1 분명히이 방법은 데이터가 db에 저장 될 때마다 추가 처리가 필요하며 더 중요한 것은 검색 문자열 맵을 저장하기위한 추가 공간이 필요하다는 것입니다.

B.2 Firestore 쿼리에 위와 같은 단일 조건이있는 경우 사전에 색인을 생성 할 필요가 없습니다. 이 솔루션은이 경우 잘 작동합니다.

B.3 그러나 쿼리에 다른 조건이있는 경우 (예 : (status === "active")) 사용자가 입력하는 각 "검색 문자열"에 대해 인덱스가 필요한 것 같습니다. 즉, 사용자가 "Jam"을 검색하고 다른 사용자가 "Butter"를 검색하면 문자열 "Jam"에 대한 인덱스를 미리 만들고 "Butter"에 대한 인덱스를 만들어야합니다. 가능한 모든 것을 예측할 수없는 경우 사용자의 검색 문자열은 작동하지 않습니다-쿼리에 다른 조건이있는 경우!

.where(searchKeywordsMap["Jam"], "==", true); // requires an index on searchKeywordsMap["Jam"]
.where("status", "==", "active");

** 방법 -C : 검색 문자열의 배열 및 "배열 포함"연산자 사용

@Albert Renshaw 제안 및 @Nick Carducci 시연

document1 = {
  'searchKeywordsArray': [
    'Jam',
    'Butter',
    'Muhamed',
    'Green District',
    'Muhamed, Green District',
  ]
}

.where("searchKeywordsArray", "array-contains", searchString); 

C.1 Method-B와 유사하게,이 방법은 데이터가 db에 저장 될 때마다 추가 처리가 필요하며 더 중요한 것은 검색 문자열 배열을 저장하기위한 추가 공간이 필요하다는 것입니다.

C.2 Firestore 쿼리는 복합 쿼리에 "array-contains"또는 "array-contains-any"절을 최대 하나만 포함 할 수 있습니다.

일반 제한 :

  1. 이러한 솔루션 중 어느 것도 부분 문자열 검색을 지원하지 않는 것 같습니다. 예를 들어, db 필드에 "1 Peter St, Green District"가 포함 된 경우 "strict"문자열을 검색 할 수 없습니다.
  2. 예상되는 검색 문자열의 가능한 모든 조합을 포함하는 것은 거의 불가능합니다. 예를 들어, db 필드에 "1 Mohamed St, Green District"가 포함 된 경우 db에서 사용 된 순서와 다른 순서로 단어가있는 문자열 인 "Green Mohamed"문자열을 검색하지 못할 수 있습니다. 들.

모든 것에 적합한 솔루션은 없습니다. 각 해결 방법에는 제한 사항이 있습니다. 위의 정보가 이러한 해결 방법 사이의 선택 과정에서 도움이되기를 바랍니다.

Firestore 쿼리 조건 목록은 https://firebase.google.com/docs/firestore/query-data/queries 문서를 확인 하세요 .

@Jonathan이 제안한 https://fireblog.io/blog/post/firestore-full-text-search 시도하지 않았습니다 .


-10

백틱을 사용하여 문자열 값을 출력 할 수 있습니다. 이것은 작동합니다.

where('name', '==', `${searchTerm}`)

감사합니다. 그러나이 질문은 정확하지 않은 값을 얻는 것에 관한 것입니다. 예를 들어, 문제의 예는 이름이 정확한지 확인합니다. 이름이 "Test"인 문서가 있고 "Test"를 검색하면 작동합니다. 그러나 "tes"또는 "est"를 검색해도 "Test"결과를 얻을 수있을 것으로 기대합니다. 책 제목이있는 사용 사례를 상상해보십시오. 사람들은 종종 정확한 제목이 아닌 부분적인 책 제목을 검색합니다.
tehfailsafe 2017

13
@suulisin 당신이 옳습니다, 내가 찾은 것을 공유하고 싶어서 조심스럽게 읽지 않았습니다. 지적 해주신 여러분의 노력에 감사 드리며 더 조심하겠습니다
Zach J
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.