Przegląd zapytań z filtrami zakresów i nierówności w wielu polach

Cloud Firestore obsługuje filtry zakresu i nierówności w wielu polach w jednym zapytaniu. Możesz stosować warunki zakresu i nierówności w wielu polach oraz uprościć tworzenie aplikacji, przekazując implementację logiki po filtrowaniu do Cloud Firestore.

Filtry zakresu i nierówności w wielu polach

To zapytanie używa filtrów zakresu dotyczących populacji i gęstości,aby zwrócić wszystkie miasta,w których populacja przekracza 1 000 000 osób,a gęstość zaludnienia jest mniejsza niż 10 000 osób na jednostkę powierzchni.

Wersja internetowa 9, modułowa

const q = query(
    collection(db, "cities"),
    where('population', '>', 1000000),
    where('density', '<', 10000),
  );

Swift

let query = db.collection("cities")
  .whereField("population", isGreaterThan: 1000000)
  .whereField("density", isLessThan: 10000)

Objective-C

FIRQuery *query =
 [[[[self.db collectionWithPath:@"cities"]
queryWhereField:@"population" isGreaterThan:@1000000]
   queryWhereField:@"density" isLessThan:@10000];

Java Android

Query query = db.collection("cities")
 .whereGreaterThan("population", 1000000)
 .whereLessThan("density", 10000);

Kotlin+KTX na Androida

val query = db.collection("cities")
 .whereGreaterThan("population", 1000000)
 .whereLessThan("density", 10000)

Go

   query := client.Collection("cities").
      Where("population", ">", 1000000).
      Where("density", "<", 10000)

Java

db.collection("cities")
  .whereGreaterThan("population", 1000000)
  .whereLessThan("density", 10000);

Node.js

db.collection("cities")
  .where('population', '>', 1000000),
  .where('density', '<', 10000)

Python

from google.cloud import firestore

db = firestore.Client()
query = db.collection("cities")
.where("population", ">", 1000000)
.where("density", "<", 10000)

PHP

$collection = $db->collection('samples/php/cities');
$chainedQuery = $collection
    ->where('population', '>', 1000000)
    ->where('density', '<', 10000);

C#

CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef
    .WhereGreaterThan("Population", 1000000)
    .WhereLessThan("Density", 10000);
QuerySnapshot querySnapshot = await query.GetSnapshotAsync();
foreach (DocumentSnapshot documentSnapshot in querySnapshot)
{
    var name = documentSnapshot.GetValue<string>("Name");
    var population = documentSnapshot.GetValue<int>("Population");
    var density = documentSnapshot.GetValue<int>("Density");
    Console.WriteLine($"City '{name}' returned by query. Population={population}; Density={density}");
}

Ruby

query = cities_ref.where("population", ">", "1000000")
                  .where("density", "<", 10000)

C++

CollectionReference cities_ref = db->Collection("cities");
Query query = cities_ref.WhereGreaterThan("population", FieldValue::Integer(1000000))
                       .WhereLessThan("density", FieldValue::Integer(10000));

Unity

CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef.WhereGreaterThan("population", 1000000)
                      .WhereLessThan("density", 10000);

Dart

final citiesRef = FirebaseFirestore.instance.collection('cities')
final query = citiesRef.where("population", isGreaterThan: 1000000)
                  .where("density", isLessThan: 10000);

Uwagi dotyczące indeksowania

Zanim uruchomisz zapytania, przeczytaj informacje o [zapytaniach][1] i Cloud Firestore [modelu danych][2].

W Cloud Firestore klauzula ORDER BY zapytania określa, które indeksy mogą być używane do obsługi zapytania. Na przykład zapytanie ORDER BY a ASC, b ASC wymaga indeksu złożonego w polach a ASC, b ASC.

Aby zoptymalizować wydajność i koszty zapytań Cloud Firestore, zoptymalizuj kolejność pól w indeksie. Aby to zrobić, upewnij się, że indeks jest uporządkowany od lewej do prawej, tak aby zapytanie było przekształcane w zbiór danych, który zapobiega skanowaniu niepotrzebnych wpisów indeksu.

Załóżmy, że chcesz przeszukać kolekcję pracowników i znaleźć pracowników w Stanach Zjednoczonych, których wynagrodzenie przekracza 100 000 USD, a liczba lat doświadczenia jest większa niż 0. Na podstawie swojej wiedzy o zbiorze danych wiesz, że ograniczenie dotyczące wynagrodzenia jest bardziej selektywne niż ograniczenie dotyczące doświadczenia. Idealnym indeksem, który zmniejszyłby liczbę skanowań indeksu, byłby (salary [...], experience [...]). Dlatego zapytanie, które będzie szybkie i opłacalne, będzie miało salary przed experience i będzie wyglądać tak:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

Node.js

db.collection("employees")
  .where("salary", ">", 100000)
  .where("experience", ">", 0)
  .orderBy("salary")
  .orderBy("experience");

Python

db.collection("employees")
  .where("salary", ">", 100000)
  .where("experience", ">", 0)
  .order_by("salary")
  .order_by("experience");

Sprawdzone metody optymalizacji indeksów

Podczas optymalizowania indeksów pamiętaj o tych sprawdzonych metodach.

Uporządkuj pola indeksu według równości, a następnie według najbardziej selektywnego zakresu lub pola nierówności.

Cloud Firestore używa pól indeksu złożonego znajdujących się najbardziej po lewej stronie, aby spełnić ograniczenia równości oraz ograniczenia zakresu lub nierówności (jeśli występują) w pierwszym polu zapytania orderBy(). Te ograniczenia mogą zmniejszyć liczbę wpisów indeksu skanowanych przez Cloud Firestore. Cloud Firestore używa pozostałych pól indeksu do spełnienia innych ograniczeń zakresu lub nierówności zapytania. Te ograniczenia nie zmniejszają liczby wpisów indeksu skanowanych przez Cloud Firestore, ale odfiltrowują niedopasowane dokumenty, dzięki czemu liczba dokumentów zwracanych klientom jest mniejsza.

Więcej informacji o tworzeniu wydajnych indeksów znajdziesz we [właściwościach indeksu][4].

Uporządkuj pola w kolejności malejącej selektywności ograniczeń zapytania.

Aby mieć pewność, że Cloud Firestore wybierze optymalny indeks dla zapytania, określ klauzulę orderBy(), która porządkuje pola w kolejności malejącej selektywności ograniczeń zapytania. Wyższa selektywność dopasowuje mniejszy podzbiór dokumentów, a niższa – większy. Upewnij się, że pola zakresu lub nierówności o wyższej selektywności są wybierane wcześniej w kolejności indeksu niż pola o niższej selektywności.

Aby zminimalizować liczbę dokumentów, które Cloud Firestore skanuje i zwraca przez sieć, zawsze porządkuj pola w kolejności malejącej selektywności ograniczeń zapytania. Jeśli zbiór wyników nie jest w wymaganej kolejności i oczekujesz, że będzie niewielki, możesz wdrożyć logikę po stronie klienta, aby zmienić jego kolejność zgodnie z oczekiwaniami.

Załóżmy na przykład, że chcesz przeszukać kolekcję pracowników, aby znaleźć pracowników w Stanach Zjednoczonych, których wynagrodzenie przekracza 100 000 USD, i uporządkować wyniki według lat doświadczenia pracownika. Jeśli spodziewasz się,że tylko niewielka liczba pracowników będzie miała wynagrodzenie wyższe niż 100 000 USD, najbardziej efektywnym sposobem zapisania zapytania jest:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .orderBy("salary")
  .get()
  .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
          // Order results by `experience`
        }
    });;

Node.js

const querySnapshot = await db.collection('employees')
                              .where("salary", ">", 100000)
                              .orderBy("salary")
                              .get();

// Order results by `experience`

Python

results = db.collection("employees")
            .where("salary", ">", 100000)
            .order_by("salary")
            .stream()

// Order results by `experience`

Dodanie do zapytania porządkowania według experience spowoduje zwrócenie tego samego zestawu dokumentów i wyeliminuje konieczność ponownego porządkowania wyników na klientach, ale zapytanie może odczytać znacznie więcej niepowiązanych wpisów indeksu niż wcześniejsze zapytanie. Dzieje się tak, ponieważ Cloud Firestore zawsze preferuje indeks, którego prefiks pól indeksu pasuje do klauzuli order by zapytania. Jeśli do klauzuli order by dodano experience, Cloud Firestore wybierze indeks (experience [...], salary [...]) do obliczania wyników zapytania. Ponieważ nie ma innych ograniczeń dotyczących experience, Cloud Firestore odczyta wszystkie wpisy indeksu kolekcji employees przed zastosowaniem filtra salary, aby znaleźć ostateczny zbiór wyników. Oznacza to, że wpisy indeksu, które nie spełniają filtra salary, są nadal odczytywane, co zwiększa czas oczekiwania i koszt zapytania.

Ceny

Zapytania z filtrami zakresu i nierówności w wielu polach są rozliczane na podstawie odczytanych dokumentów i wpisów indeksu.

Szczegółowe informacje znajdziesz na stronie [Ceny][5].

Ograniczenia

Oprócz [ograniczeń dotyczących zapytań][6] przed użyciem zapytań z filtrami zakresu i nierówności w wielu polach weź pod uwagę te ograniczenia:

  • Zapytania z filtrami zakresu lub nierówności w polach dokumentu i tylko ograniczeniami równości w kluczu dokumentu (__name__) nie są obsługiwane.
  • Cloud Firestore ogranicza liczbę pól zakresu lub nierówności do 10. Ma to zapobiec zbyt wysokim kosztom uruchamiania zapytań.

Co dalej?

  • Dowiedz się więcej o [optymalizowaniu zapytań][3].
  • Dowiedz się więcej o [wykonywaniu prostych i złożonych zapytań][8].
  • Dowiedz się, jak [Cloud Firestore używa indeksów][9].

[1]: /docs/firestore/query-data/get-data [2]: /docs/firestore/data-model [3]: /docs/firestore/query-data/multiple-range-optimize-indexes [4]: /docs/firestore/concepts/index-overview#index_properties [5]: /docs/firestore/pricing [6]: /docs/firestore/query-data/queries#query_limitations [7]: https://en.wikipedia.org/wiki/Disjunctive_normal_form [8]: /docs/firestore/query-data/queries [9]: /docs/firestore/concepts/index-overview [10]: /docs/firestore/query-data/multiple-range-optimize-indexes