Panoramica delle query con filtri di intervallo e disuguaglianza su più campi

Cloud Firestore supporta l'utilizzo di filtri di intervallo e di disuguaglianza su più campi in una singola query. Puoi avere condizioni di intervallo e di disuguaglianza su più campi e semplificare lo sviluppo dell'applicazione delegando l'implementazione della logica di post-filtraggio a Cloud Firestore.

Filtri di intervallo e di disuguaglianza su più campi

La seguente query utilizza filtri di intervallo su popolazione e densità per restituire tutte le città in cui la popolazione è superiore a 1.000.000 di persone e la densità di popolazione è inferiore a 10.000 persone per unità di area.

Versione web modulare 9

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 Android

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

Vai

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

Considerazioni sull'indicizzazione

Prima di eseguire le query, leggi le informazioni sulle query e sul Cloud Firestore modello di dati.

In Cloud Firestore, la clausola ORDER BY di una query determina quali indici possono essere utilizzati per eseguire la query. Ad esempio, una query ORDER BY a ASC, b ASC richiede un indice composto sui campi a ASC, b ASC.

Per ottimizzare le prestazioni e il costo delle query Cloud Firestore, ottimizza l'ordine dei campi nell'indice. Per farlo, assicurati che l'indice sia ordinato da sinistra a destra in modo che la query si riduca a un set di dati che impedisca la scansione di voci di indice non necessarie.

Supponiamo che tu voglia cercare in una raccolta di dipendenti e trovare i dipendenti degli Stati Uniti il cui stipendio è superiore a 100.000 $e il cui numero di anni di esperienza è maggiore di 0. In base alla tua conoscenza del set di dati, sai che il vincolo dello stipendio è più selettivo del vincolo dell'esperienza. L'indice ideale che ridurrebbe il numero di scansioni dell'indice sarebbe (salary [...], experience [...]). Pertanto, la query che sarebbe veloce ed economica ordinerebbe salary prima di experience e avrebbe il seguente aspetto:

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");

Best practice per l'ottimizzazione degli indici

Quando ottimizzi gli indici, tieni presente le seguenti best practice.

Ordina i campi dell'indice in base alle uguaglianze, seguite dal campo di intervallo o di disuguaglianza più selettivo

Cloud Firestore utilizza i campi più a sinistra di un indice composto per soddisfare i vincoli di uguaglianza e il vincolo di intervallo o di disuguaglianza, se presente, sul primo campo della orderBy() query. Questi vincoli possono ridurre il numero di voci di indice scansionate da Cloud Firestore. Cloud Firestore utilizza i campi rimanenti dell'indice per soddisfare altri vincoli di intervallo o di disuguaglianza della query. Questi vincoli non riducono il numero di voci di indice scansionate da Cloud Firestore ma filtrano i documenti non corrispondenti in modo da ridurre il numero di documenti restituiti ai client.

Per saperne di più sulla creazione di indici efficienti, consulta Proprietà dell'indice.

Ordina i campi in ordine decrescente di selettività dei vincoli di query

Per assicurarti che Cloud Firestore selezioni l'indice ottimale per la tua query, specifica una clausola orderBy() che ordina i campi in ordine decrescente di selettività dei vincoli di query. Una selettività più elevata corrisponde a un sottoinsieme più piccolo di documenti, mentre una selettività inferiore corrisponde a un sottoinsieme più grande di documenti. Assicurati di selezionare i campi di intervallo o di disuguaglianza con una selettività più elevata all'inizio dell'ordinamento dell'indice rispetto ai campi con una selettività inferiore.

Per ridurre al minimo il numero di documenti che Cloud Firestore scansiona e restituisce sulla rete, devi sempre ordinare i campi in ordine decrescente di selettività dei vincoli di query. Se il set di risultati non è nell'ordine richiesto e si prevede che sia piccolo, puoi implementare la logica lato client per riordinarlo in base alle tue aspettative di ordinamento.

Ad esempio, supponiamo che tu voglia cercare in una raccolta di dipendenti per trovare i dipendenti degli Stati Uniti il cui stipendio è superiore a 100.000 $e ordinare i risultati in base all'anno di esperienza del dipendente. Se prevedi che solo un piccolo numero di dipendenti avrà uno stipendio superiore a 100.000 $, il modo più efficiente per scrivere la query è il seguente:

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`

Sebbene l'aggiunta di un ordinamento in base a experience alla query produca lo stesso insieme di documenti ed eviti di riordinare i risultati sui client, la query potrebbe leggere molte più voci di indice estranee rispetto alla query precedente. Questo perché Cloud Firestore preferisce sempre un indice i cui campi di indice corrispondono al prefisso della clausola order by della query. Se experience viene aggiunto alla clausola order by, allora Cloud Firestore selezionerà l'indice (experience [...], salary [...]) per calcolare i risultati della query. Poiché non esistono altri vincoli su experience, Cloud Firestore leggerà tutte le voci di indice della employees raccolta prima di applicare il salary filtro per trovare il set di risultati finale. Ciò significa che le voci di indice che non soddisfano il filtro salary vengono comunque lette, aumentando così la latenza e il costo della query.

Prezzi

Le query con filtri di intervallo e di disuguaglianza su più campi vengono fatturate in base ai documenti letti e alle voci di indice lette.

Per informazioni dettagliate, consulta la pagina Prezzi.

Limitazioni

Oltre alle limitazioni delle query, tieni presente le seguenti limitazioni prima di utilizzare le query con filtri di intervallo e di disuguaglianza su più campi:

  • Le query con filtri di intervallo o di disuguaglianza sui campi dei documenti e solo vincoli di uguaglianza sulla chiave del documento (__name__) non sono supportate.
  • Cloud Firestore limita a 10 il numero di campi di intervallo o di disuguaglianza. Questo per evitare che le query diventino troppo costose da eseguire.

Passaggi successivi