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

Cloud Firestore obsługuje stosowanie filtrów 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, delegując implementację logiki po filtrowaniu do funkcji Cloud Firestore.

Filtry zakresu i nierówności na wielu polach

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

Wersja internetowa 9 modular

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 na Androida

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

Kotlin + KTX na Androidzie

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, zapoznaj się z informacjami o zapytaniachmodelu danych Cloud Firestore.

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 na polach a ASC, b ASC.

Aby zoptymalizować wydajność i koszt zapytań Cloud Firestore, zoptymalizuj kolejność pól w indeksie. Aby to zrobić, sprawdź, czy indeks jest uporządkowany od lewej do prawej, tak aby zapytanie prowadziło do zbioru danych, który zapobiega skanowaniu niepotrzebnych wpisów indeksu.

Załóżmy, że chcesz przeszukać zbiory pracowników i znaleźć tych w Stanach Zjednoczonych, których wynagrodzenie przekracza 100 tys. USD, a ich doświadczenie zawodowe jest dłuższe niż 0 lat. Na podstawie swoich obserwacji dotyczących zbioru 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 wydajne kosztowo, będzie porządkować 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.

Sortowanie pól indeksu według równań, a następnie według najbardziej selektywnego zakresu lub pola nierówności

Zapytanie Cloud Firestore używa pól znajdujących się najdalej w lewą stronę w indeksie złożonym, aby spełnić ograniczenia równości i zakresu lub ograniczenia nierówności (jeśli występują) w pierwszym polu zapytania orderBy(). Te ograniczenia mogą zmniejszyć liczbę indeksowanych pozycji, które Cloud Firestore skanuje. Cloud Firestore używa pozostałych pól indeksu do zaspokajania innych ograniczeń zakresu lub nierówności zapytania. Te ograniczenia nie zmniejszają liczby pozycji indeksu skanowanych przez Cloud Firestore, ale odfiltrowują niepasujące dokumenty, dzięki czemu zmniejsza się liczba dokumentów zwracanych klientom.

Więcej informacji o tworzeniu wydajnych indeksów znajdziesz w artykule Właściwości indeksu.

Polecenia sortowania pól według malejącej selektywności ograniczeń zapytań

Aby zapytanie Cloud Firestore wybierało optymalny indeks, określ klauzulę orderBy(), która porządkuje pola w malejącym porządku selektywności ograniczeń zapytania. Większa selektywność oznacza dopasowanie do mniejszego podzbioru dokumentów, a mniejsza – do większego podzbioru dokumentów. Pamiętaj, aby wybierać pola zakresu lub nierówności o większej selektywności wcześniej w porządku indeksowania niż pola o mniejszej selektywności.

Aby zminimalizować liczbę dokumentów, które Cloud Firestoreskanuje i zwraca w sieci, zawsze należy uporządkować pola w malejącym porządku selektywności ograniczeń zapytań. Jeśli zbiór wyników nie jest uporządkowany w wymaganej kolejności i oczekujesz, że zbiór wyników będzie mały, możesz zastosować logikę po stronie klienta, aby uporządkować go zgodnie z Twoimi oczekiwaniami.

Załóżmy na przykład, że chcesz przeszukać kolekcję pracowników, aby znaleźć tych, którzy zarabiają ponad 100 tys. USD i mają doświadczenie zawodowe dłuższe niż 1 rok. Chcesz też, aby wyniki były uporządkowane według tego ostatniego kryterium. Jeśli spodziewasz się,że tylko niewielka liczba pracowników będzie miała pensje powyżej 100 tys. USD, najskuteczniejszym sposobem sformułowania zapytania będzie:

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 sortowania według experience spowoduje zwrócenie tego samego zbioru dokumentów i wyeliminuje konieczność ponownego sortowania wyników na klientach, ale zapytanie może odczytać znacznie więcej nieistotnych wpisów indeksu niż poprzednie 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 kolumnę experience, funkcja Cloud Firestore wybierze indeks (experience [...], salary [...]) do obliczenia wyników zapytania. Ponieważ nie ma żadnych innych ograniczeń dotyczących zapytania experience, przed zastosowaniem filtra salary Cloud Firestore odczyta wszystkie wpisy indeksu kolekcji employees, aby znaleźć ostateczny zbiór wyników. Oznacza to, że wpisy indeksu, które nie spełniają kryterium filtra salary, są nadal odczytywane, co zwiększa opóźnienie i koszt zapytania.

Ceny

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

Szczegółowe informacje znajdziesz na stronie Ceny.

Ograniczenia

Zanim użyjesz zapytań z filtrami zakresu i nierówności w kilku polach, pamiętaj o tych ograniczeniach (oprócz ograniczeń dotyczących zapytań):

  • Zapytania z filtrami zakresu lub nierówności w polach dokumentu oraz 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 zapytań.

Co dalej?