Google Firestore: Bir özellik değerinin alt dizesi üzerinde sorgu (metin arama)


112

Basit bir arama alanı eklemek istiyorum, gibi bir şey kullanmak istiyorum

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

Kullanmayı denedim where('name', '==', '%searchTerm%'), ama hiçbir şey döndürmedi.


1
Firebase artık bunu destekliyor. Lütfen yanıtı güncelleyin: stackoverflow.com/a/52715590/2057171
Albert Renshaw

1
Bence en iyi yol, her belgeyi manuel olarak indeksleyen bir komut dosyası oluşturmaktır. Ardından bu dizinleri sorgulayın. şuna bir
Kiblawi_Rabee

Yanıtlar:


42

Böyle operatör yok, evcil olanlar ==, <, <=, >, >=.

Yalnızca öneklere göre filtreleyebilirsiniz, örneğin, aralarında başlayan barve fookullanabileceğiniz her şey için

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

Bunun için Algolia veya ElasticSearch gibi harici hizmetleri kullanabilirsiniz .


6
Tam olarak aradığım bu değil. Uzun başlıkları olan geniş bir ürün listem var. "Rebok Erkek Tenis Raketi". Bir kullanıcı arayabilir tennis, ancak mevcut sorgu operatörlerine göre bu sonuçları almanın bir yolu yoktur. Birleştiriyor >=ve <=çalışmıyor. Elbette Algolia'yı kullanabilirim, ancak çoğu soruyu yapmak için Firebase ile de kullanabilirim ve Firestore'a
geçmeme

5
@tehfailsafe Peki sorunuz 'bir alan bir dizge içeriyorsa nasıl sorgulanır' ve yanıt 'bunu yapamazsınız'.
Kuba

21
@ A.Chakroun Cevabımda tam olarak kaba olan nedir?
Kuba

20
tbh bu gerçekten gerekli bir şey. Firebase ekibinin neden bunu düşünmediğini anlayamıyorum
Dani

2
Firebase'in sorgulama konusunda çok zayıf olması gerçekten şaşırtıcı. Bu kadar basit bir sorguyu destekleyemiyorsa, bu kadar çok insanın onu kullandığına inanamıyorum.
Bagusflyer

51

@ Kuba'nın cevabına katılıyorum, Ancak yine de, öneke göre arama için mükemmel bir şekilde çalışması için küçük bir değişiklik eklemesi gerekiyor. burada benim için işe yarayan

İsim ile başlayan kayıtları aramak için queryText

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

\uf8ffSorguda kullanılan karakter , Unicode aralığında çok yüksek bir kod noktasıdır (Özel Kullanım Alanı [PUA] kodudur). Unicode'daki çoğu normal karakterden sonra olduğu için, sorgu ile başlayan tüm değerlerle eşleşir queryText.


2
Güzel yanıt !, bu, önek metninin aranması için harika çalışıyor. Metindeki kelimeleri aramak için, bu yazıda açıklandığı gibi "dizi içeren" uygulamasını deneyebilirsiniz medium.com/@ken11zer01/…
guillefd

Düşünüyorum, ama teorik olarak başka bir alan oluşturarak ve verileri ters çevirerek queryTest ile biten tüm değerleri eşleştirebilirsin ...
Jonathan

Evet @Jonathan, bu da mümkün.
Ankit Prajapati

43

Kuba'nın cevabı, kısıtlamalar söz konusu olduğunda doğru olsa da, bunu set benzeri bir yapıyla kısmen taklit edebilirsiniz:

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

Şimdi ile sorgulayabilirsiniz

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

Bu işe yarar çünkü Firestore her alan için otomatik olarak bir dizin oluşturacaktır. Maalesef bu, doğrudan bileşik sorgular için çalışmaz çünkü Firestore otomatik olarak bileşik dizinler oluşturmaz.

Yine de kelime kombinasyonlarını saklayarak bu sorunu çözebilirsiniz, ancak bu çirkinleşir.

Dıştan takmalı bir tam metin aramasıyla muhtemelen daha iyi durumdasınız .


Cloud.google.com/appengine/docs/standard/java/search ile bulut işlevini kullanmak mümkün ?
Henry

1
Bunu bu cevabın devamı olarak soruyorsanız: AppEngine'in tam metin araması Firestore'dan tamamen ayrıdır ve bu nedenle bu size doğrudan yardımcı olmaz. Verilerinizi bir bulut işlevi kullanarak çoğaltabilirsiniz, ancak esasen dıştan takma tam metin aramayı kullanma önerisi budur. Başka bir şey soruyorsanız, lütfen yeni bir soru başlatın.
Gil Gilbert

1
Firestore'da, kullanmadan önce tüm terimleri dizine eklemeniz gerekirwhere
Husam

4
Husam'ın da belirttiği gibi, tüm bu alanların indekslenmesi gerekecekti. Ürün adımın içerdiği herhangi bir terimi aramayı etkinleştirmek istedim. Bu yüzden, belgemde, ürün adının parçaları olan ve her biri kendisine atanmış 'true' değerine sahip anahtarlarla bir 'nesne' türü özelliği oluşturdum, nerede aramanın ('nameSegments.tennis', '==', true) olacağını umarak work, ancak firestore diğer her terim için aynı olan nameSegments.tennis için bir dizin oluşturmayı önerir. Sonsuz sayıda terim olabileceğinden, bu yanıt yalnızca tüm arama terimleri önceden tanımlandığında çok sınırlı bir senaryo için kullanılabilir.
Slawoj

2
@epeleg Sorgu, bunun için bir dizin oluşturduktan sonra işe yarayacaktı, ancak ürün adınızın içerdiği olası her terim için dizin oluşturmak mümkün değildir, bu nedenle ürün adlarında terimlerin metin araması için bu yaklaşım benim durumum için işe yaramadı.
Slawoj

31

Firebase, bir dize içinde bir terimin aranmasını açıkça desteklemese de,

Firebase, (şimdi) sizin durumunuz ve diğerleri için çözecek olan aşağıdakileri desteklemektedir:

Ağustos 2018 itibariyle array-containssorguyu destekliyorlar . Bakınız: https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html

Artık tüm anahtar terimlerinizi alan olarak bir diziye ayarlayabilir ve ardından 'X' içeren bir diziye sahip tüm belgeleri sorgulayabilirsiniz. Ek sorgular için daha fazla karşılaştırma yapmak için mantıksal VE'yi kullanabilirsiniz . (Bunun nedeni, firebase'in şu anda birden fazla dizi içeren sorgu için bileşik sorguları yerel olarak desteklememesidir, bu nedenle 'VE' sıralama sorgularının istemci tarafında yapılması gerekir)

Dizileri bu tarzda kullanmak, eşzamanlı yazmalar için optimize edilmelerine izin verir ki bu da güzeldir! Toplu istekleri destekleyip desteklemediğini test etmedim (dokümanlar söylemez) ancak resmi bir çözüm olduğu için yaptığına bahse girerim.


Kullanım:

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

13
Bu güzel bir çözüm. Ancak, yanılıyorsam düzeltin, ancak @tehfailsafe'nin istediğini yapmanıza izin vermediğini düşünüyorum. Örneğin, "abc" dizesini içeren tüm isimleri almak istiyorsanız, dizi-içerir ile herhangi bir başarı elde edemezsiniz, çünkü yalnızca "abc" tam adını taşıyan ancak "abcD" veya "0abc" çıkardı.
Yulian

1
@Yulian Programlama dünyasında, Search termtipik olarak her iki tarafta boşluk, noktalama vb. İle ayrılmış tam bir terim olarak anlaşılır. Eğer google Eğer abcdeşu anda yalnızca gibi şeyler için sonuçlar bulacaksınız %20abcde.ya ,abcde!ama abcdefghijk... Her ne kadar yazılan alfabenin tamamı internette çok daha yaygın olsa da, arama abcde için değil * izole bir abcde için
Albert Renshaw

1
Ne 'contains'demek istediğini anlıyorum ve buna katılıyorum, ama muhtemelen kelimeyle yanıldım , bu da birçok programlama dilinde tam olarak bahsettiğim anlamına geliyor. Aynı şey '%searchTerm%'SQL açısından da geçerli.
Yulian

2
@Yulian Evet anladım. Firebase, NoSQL olsa da, bu tür işlemleri hızlı ve verimli hale getirmede gerçekten iyidir, joker karakter dizisi arama gibi bazı kapsam dışı sorunlar için sınırlı olsalar bile.
Albert Renshaw

2
Pekala, belgeyi her güncellediğinizde titleArray: ['bu', 'eşittir', 'a', 'başlık'] gibi bölünmüş kelimelerin temsiliyle her biri için ayrı bir alan oluşturabilirsiniz. Ve sonra arama, başlık yerine o alana göre yapılacaktır. Bu alanları oluşturmak için Update'te soğuk bir triiger oluşturun. Arama tabanlı metin için çok çalışma var, ancak NoSQL'in performans iyileştirmelerini tercih ediyorum.
sfratini

16

Başına Firestore docs , Bulut Firestore yerli indeksleme desteklemiyor veya belgelerde metin alanları arayın. Ek olarak, istemci tarafında alanları aramak için bir koleksiyonun tamamını indirmek pratik değildir.

Algolia ve Elastic Search gibi üçüncü taraf arama çözümleri önerilir.


49
İdeal olmasa da dokümanları okudum. Dezavantajı, Algolia ve Firestore'un farklı fiyatlandırma modellerine sahip olmasıdır ... Firestore'da mutlu bir şekilde 600.000 belgeye sahip olabilirim (günde çok fazla sorgulamadığım sürece). Onları arama yapmak için Algolia'ya gönderdiğimde, şimdi sadece Firestore belgelerim üzerinde bir başlık araması yapabilmek için Algolia'ya ayda 310 $ ödemek zorunda kalıyorum.
tehfailsafe

2
sorun şu ki bu bedava değil
Dani

Bu sorulan sorunun doğru cevabıdır ve en iyi olarak kabul edilmelidir.
briznad

13

Burada birkaç not:

1.) \uf8ff aynı şekilde çalışır~

2.) Where cümlesini veya start end cümlelerini kullanabilirsiniz:

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

tamamen aynı

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

3.) Hayır, tersine çevirirseniz startAt()ve endAt()her kombinasyonda çalışmaz , ancak tersine ikinci bir arama alanı oluşturarak ve sonuçları birleştirerek aynı sonucu elde edebilirsiniz.

Örnek: Öncelikle, alan oluşturulduğunda alanın tersine çevrilmiş bir versiyonunu kaydetmelisiniz. Bunun gibi bir şey:

// 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);
}

Bununla, rastgele orta harfleri veya harf gruplarını değil, bir dize alanının son harflerini ve ilkini arayabilirsiniz . Bu istenen sonuca daha yakın. Ancak, rastgele orta harfler veya kelimeler istediğimizde bu bize gerçekten yardımcı olmayacaktır. Ayrıca, arama için her şeyi küçük harfli veya küçük harfli bir kopyayı kaydetmeyi unutmayın, böylece büyük / küçük harf sorunu bir sorun olmaz.

4.) Yalnızca birkaç kelimeniz varsa, Ken Tan'ın Yöntemi istediğiniz her şeyi yapacaktır veya en azından biraz değiştirdikten sonra. Ancak, yalnızca bir paragraf metniyle katlanarak 1MB'den fazla veri oluşturacaksınız, bu da firestore'un belge boyutu sınırından daha büyüktür (biliyorum, test ettim).

5.) Dizi içeren (veya bir dizi diziyi) \uf8ffhile ile birleştirebilseydiniz , sınırlara ulaşmayan uygun bir arama yapabilirsiniz. Haritalarla bile her kombinasyonu denedim ve hayır. Bunu anlarsanız, buraya gönderin.

6.) ALGOLIA ve ELASTIC SEARCH'ten uzaklaşmanız gerekiyorsa ve sizi hiç suçlamıyorum, Google Cloud'da her zaman mySQL, postSQL veya neo4J'leri kullanabilirsiniz. Bunların 3'ü de kurulumu kolaydır ve ücretsiz katmanları vardır. Verileri onCreate () kaydetmek için bir bulut işlevine ve verileri aramak için başka bir onCall () işlevine sahip olursunuz. Basit ... ish. O halde neden mySQL'e geçmiyorsunuz? Tabii ki gerçek zamanlı veriler! Birisi gerçek zamanlı veriler için web çoraplarıyla DGraph yazdığında beni de hesaba katın!

Algolia ve ElasticSearch yalnızca arama özellikli dbs olarak tasarlandı, bu yüzden bu kadar hızlı bir şey yok ... ama parasını ödüyorsunuz. Google, neden bizi Google'dan uzaklaştırıyorsun ve MongoDB noSQL'i takip edip aramalara izin vermiyor musun?

GÜNCELLEME - BİR ÇÖZÜM YARATTIM:

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


Harika bir genel bakış ve çok faydalı.
RedFilter

Harika! İyi yapılandırılmış ve bilgilendirici bir yanıt için oy verin.
Jungle King Of

11

Geç cevap ama hala bir cevap arayanlar için, Diyelim ki bir kullanıcı koleksiyonumuz var ve koleksiyonun her bir belgesinde bir "kullanıcı adı" alanımız var, bu nedenle kullanıcı adının "al" ile başladığı bir belge bulmak istiyorsanız gibi bir şey yapabiliriz

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

bu harika bir kolay çözüm, teşekkür ederim. Peki ya birden fazla alanı kontrol etmek isterseniz. Bir VEYA ile bağlanan "ad" ve "açıklama" gibi mi?
deneyin

İki alana göre sorgulama yapabileceğinizi sanmıyorum, ne yazık ki, sorgulama söz konusu olduğunda firebase kötüdür, bu umudu kontrol edebilirsiniz, stackoverflow.com/questions/26700924/…
MoTahir

1
Onaylandı, @MoTahir. Firestore'da "VEYA" yoktur.
Rap

bu çözüm "al" ile başlayan kullanıcı adlarıyla eşleşmiyor ... örneğin "merhaba" eşleşecek ("merhaba"> "al")
antoine129

OR ile sorgulama, iki arama sonucunu birleştirme meselesidir. Bu sonuçları sıralamak farklı bir problem ...
Jonathan

7

Eminim Firebase, dizedeki herhangi bir dizini [i] startAt yakalamak için yakında "string-contains" ile çıkacaktır ... Ancak web'leri araştırdım ve başka biri tarafından verilerinizi ayarlayan bu çözümü buldum bu

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
})

görüntü açıklamasını buraya girin

bunun gibi sorgu

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

Hiç tavsiye edilmez. Belgelerin 20.000 satır sınırı olduğundan, belgenizin asla bu sınırlara ulaşmayacağından emin olana kadar bu şekilde kullanamazsınız
Sandeep

Şu anda en iyi seçenek bu, başka ne önerilir?
Nick Carducci

1
@Sandeep Bu boyutun belge başına 1MB boyut ve 20 derinlik seviyesi ile sınırlı olduğundan oldukça eminim. 20 bin satırla ne demek istiyorsun? Algolia veya ElasticSearch kullanılıyorsa şu anda en iyi çözüm budur
ppicom

6

Algolia gibi üçüncü taraf bir hizmeti kullanmak istemiyorsanız, Firebase Cloud Functions harika bir alternatiftir. Bir girdi parametresi alabilen, sunucu tarafındaki kayıtlar üzerinden işleyebilen ve ardından kriterlerinize uyanları döndürebilen bir işlev oluşturabilirsiniz.


1
Peki ya android?
Pratik Butani

İnsanların bir koleksiyondaki her bir kaydı yinelemesini mi öneriyorsunuz?
DarkNeuron

Pek sayılmaz. Array.prototype kullanırım. * - .every (), .some (), .map (), .filter () vb. Gibi. Bu, sunucuya değerleri döndürmeden önce bir Firebase İşlevi içinde müşteri.
Rap

4
Bunları aramak için yine de TÜM belgeleri okumanız gerekir, bu masraflara neden olur ve Zaman için pahalıdır.
Jonathan

4

Seçilen yanıt yalnızca tam aramalar için işe yarar ve doğal kullanıcı arama davranışı değildir ("Joe bugün bir elma yedi" içinde "elma" araması işe yaramaz).

Dan Fein'in yukarıdaki cevabının daha üst sıralarda yer alması gerektiğini düşünüyorum. Aradığınız Dize verileri kısaysa dizenin tüm alt dizelerini Belgenizdeki bir diziye kaydedebilir ve ardından Firebase'in array_contains sorgusuyla dizi içinde arama yapabilirsiniz. Firebase Belgeleri, bir belgede kaydedilen yaklaşık 1 milyon karakter olan 1 MiB (1.048.576 bayt) ( Firebase Kotaları ve Sınırları ) ile sınırlıdır (sanırım 1 karakter ~ = 1 bayt). Belgeniz 1 milyon işarete yakın olmadığı sürece alt dizeleri saklamak sorun değildir.

Kullanıcı adlarını aramak için örnek:

Adım 1: Aşağıdaki String uzantısını projenize ekleyin. Bu, bir dizeyi kolayca alt dizelere ayırmanıza olanak tanır. ( Bunu burada buldum ).

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])
}

Adım 2: Bir kullanıcının adını kaydettiğinizde, bu işlevin sonucunu da aynı Belgede bir dizi olarak saklayın. Bu, orijinal metnin tüm varyasyonlarını oluşturur ve bunları bir dizide saklar. Örneğin, "Apple" metin girişi şu diziyi oluşturur: ["a", "p", "p", "l", "e", "ap", "pp", "pl", "le "," uygulama "," ppl "," ple "," appl "," pple "," apple "], bir kullanıcının girebileceği tüm arama kriterlerini kapsamalıdır. Tüm sonuçları istiyorsanız maximumStringSize'ı nil olarak bırakabilirsiniz, ancak uzun bir metin varsa, belge boyutu çok büyük olmadan önce onu kapatmanızı tavsiye ederim - 15 civarı benim için iyi çalışıyor (çoğu insan zaten uzun cümleleri aramıyor ).

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. Adım: Firebase'in array_contains işlevini kullanabilirsiniz!

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

3

Aslında bunu Firestore'da yapmanın en iyi çözümünün tüm alt dizeleri bir diziye koymak ve sadece bir array_contains sorgusu yapmak olduğunu düşünüyorum. Bu, alt dize eşlemesi yapmanızı sağlar. Tüm alt dizeleri depolamak biraz fazla olabilir, ancak arama terimleriniz kısaysa çok makul.


2

Bu sorunu yeni yaşadım ve oldukça basit bir çözüm buldum.

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

İsGreaterThanOrEqualTo, aramamızın başlangıcını filtrelememize ve isLessThanOrEqualTo'nun sonuna bir "z" ekleyerek aramamızı sonraki belgelere geçmeyecek şekilde sınırlandırmamıza izin verir.


3
Bu çözümü denedim, ancak benim için yalnızca tam dizi girildiğinde çalışıyor. Örneğin, "bedava" terimini almak istersem, "fr" yazmaya başlarsam hiçbir şey geri dönmez. "Ücretsiz" yazdıktan sonra terim bana anlık görüntüsünü veriyor.
Chris

Aynı kod formatını mı kullanıyorsunuz? Ve terim firestore'da bir dizge mi? DocumentId'ye göre filtre uygulayamayacağınızı biliyorum.
Jacob Bonk

0

Firestore ile tam metin araması uygulayabilirsiniz, ancak yine de normalde olduğundan daha fazla okumaya mal olacak ve ayrıca verileri belirli bir şekilde girmeniz ve dizine eklemeniz gerekecek, bu nedenle bu yaklaşımda, firebase bulut işlevlerini kullanarak belirteçleştirin ve ardından h(x)aşağıdakileri karşılayan doğrusal bir hash işlevi seçerken giriş metninizi hashleyin - if x < y < z then h(x) < h (y) < h(z). Simgeleştirme için, işlevinizin soğuk başlama zamanını düşük tutmak için bazı hafif NLP Kitaplıkları seçebilirsiniz; bu, gereksiz sözcükleri cümlenizden çıkarabilir. Daha sonra Firestore'da küçüktür ve büyüktür operatörüyle bir sorgu çalıştırabilirsiniz. Verilerinizi de depolarken, saklamadan önce metne hash uyguladığınızdan emin olmalısınız ve düz metni değiştirirseniz hashing değeri de değişecek gibi düz metni depolamalısınız.


0

Bu benim için mükemmel çalıştı ancak performans sorunlarına neden olabilir.

Firestore'u sorgularken bunu yapın:

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

Bunu FutureBuilder'ınızda yapın:

    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

Bugün itibariyle, sorunun cevabı olarak uzmanlar tarafından önerilen temelde 3 farklı geçici çözüm bulunmaktadır.

Hepsini denedim. Her biriyle olan deneyimlerimi belgelemenin yararlı olabileceğini düşündüm.

Yöntem-A: (dbField "> =" searchString) & (dbField "<=" searchString + "\ uf8ff") kullanarak

@Kuba & @Ankit Prajapati tarafından önerildi

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

A.1 Firestore sorguları, tek bir alanda yalnızca aralık filtreleri (>, <,> =, <=) gerçekleştirebilir. Birden çok alanda aralık filtrelerine sahip sorgular desteklenmez. Bu yöntemi kullanarak, db üzerindeki başka herhangi bir alanda, örneğin bir tarih alanında bir aralık operatörüne sahip olamazsınız.

A.2. Bu yöntem aynı anda birden çok alanda arama yapmak için ÇALIŞMAZ. Örneğin, dosyalardan herhangi birinde (ad, notlar ve adres) bir arama dizesi olup olmadığını kontrol edemezsiniz.

Yöntem-B: Haritadaki her giriş için "true" ile arama dizelerinin MAP'ini kullanma ve sorgularda "==" operatörünü kullanma

@Gil Gilbert tarafından önerildi

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

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

B.1 Açıktır ki, bu yöntem veri veritabanına her kaydedildiğinde ekstra işlem gerektirir ve daha da önemlisi, arama dizelerinin haritasını depolamak için fazladan alan gerektirir.

B.2 Bir Firestore sorgusu yukarıdaki gibi tek bir koşula sahipse, önceden indeks oluşturulmasına gerek yoktur. Bu çözüm, bu durumda gayet iyi çalışır.

B.3 Ancak, sorgunun başka bir koşulu varsa, örneğin (durum === "aktif"), kullanıcının girdiği her "arama dizisi" için bir indeks gerekli gibi görünür. Başka bir deyişle, bir kullanıcı "Reçel" için arama yaparsa ve başka bir kullanıcı "Tereyağı" için arama yaparsa, önceden "Reçel" dizesi için ve "Tereyağı" için başka bir dizin oluşturulmalıdır. Tüm olasılıkları tahmin edemediğiniz sürece kullanıcıların arama dizeleri, bu ÇALIŞMAZ - sorgunun başka koşulları olması durumunda!

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

** Yöntem-C: ARRAY arama dizelerini ve "dizi içerir" operatörünü kullanma

@Albert Renshaw tarafından önerildi ve @Nick Carducci tarafından gösterildi

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

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

C.1 Yöntem-B'ye benzer şekilde, bu yöntem veri veritabanına her kaydedildiğinde fazladan işlem gerektirir ve daha da önemlisi, arama dizgilerinin dizisini depolamak için fazladan alan gerektirir.

C.2 Firestore sorguları, bir bileşik sorguda en fazla bir "dizi içerir" veya "dizi içerir-herhangi bir" cümlesi içerebilir.

Genel Sınırlamalar:

  1. Bu çözümlerin hiçbiri kısmi dizelerin aranmasını desteklemiyor gibi görünüyor. Örneğin, bir db alanı "1 Peter St, Green District" içeriyorsa, "katı" dizesini arayamazsınız.
  2. Beklenen arama dizelerinin tüm olası kombinasyonlarını kapsamak neredeyse imkansızdır. Örneğin, bir db alanı "1 Mohamed St, Green District" içeriyorsa, kelimeleri db'de kullanılan sıralamadan farklı bir sıraya sahip bir dize olan "Yeşil Mohamed" dizesini arayamayabilirsiniz. alan.

Her şeye uyan tek bir çözüm yok. Her geçici çözümün kendi sınırlamaları vardır. Umarım yukarıdaki bilgiler, bu geçici çözümler arasındaki seçim sürecinde size yardımcı olabilir.

Firestore sorgu koşullarının listesi için lütfen https://firebase.google.com/docs/firestore/query-data/queries belgelerine bakın. .

@Jonathan tarafından önerilen https://fireblog.io/blog/post/firestore-full-text-search'ü denemedim .


-10

Bir dizenin değerini yazdırmak için geri tik işaretini kullanabiliriz. Bu çalışmalı:

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

Teşekkürler, ama bu soru kesin olmayan değerler almakla ilgili. Örneğin, söz konusu örnek, adın tam olup olmadığını bulmak için işe yarıyor. "Test" adlı bir dokümanım varsa ve ardından "Test" için arama yaparsam işe yarıyor. Ancak "tes" veya "est" i arayabilmeyi ve yine de "Test" sonucunu almayı bekliyorum. Kitap başlıkları içeren bir kullanım örneği hayal edin. İnsanlar genellikle tam olarak kesin başlık yerine kısmi kitap başlıkları ararlar.
tehfailsafe

14
@suulisin haklısın, bulduklarımı paylaşmaya can attığım için dikkatli okumadım. Bunu belirtme çabanız için teşekkür ederim ve daha dikkatli olacağım
Zach J
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.