Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder – Übersicht

Cloud Firestore unterstützt die Verwendung von Bereichs- und Ungleichheitsfiltern für mehrere Felder in einer einzelnen Abfrage. Sie können Bereichs- und Ungleichheitsbedingungen für mehrere Felder festlegen und die Anwendungsentwicklung vereinfachen, indem Sie die Implementierung der Nachfilterungslogik an Cloud Firestore delegieren.

Bereichs- und Ungleichheitsfilter für mehrere Felder

In der folgenden Abfrage werden Bereichsfilter für Bevölkerung und Bevölkerungsdichte verwendet, um alle Städte zurückzugeben, in denen die Bevölkerung mehr als 1.000.000 Personen beträgt und die Bevölkerungsdichte weniger als 10.000 Personen pro Flächeneinheit beträgt.

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

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

Einheit

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

Überlegungen zur Indexierung

Lesen Sie sich vor dem Ausführen Ihrer Abfragen die Informationen zu Abfragen und zum Cloud Firestore Datenmodell durch.

In Cloud Firestore bestimmt die ORDER BY-Klausel einer Abfrage, welche Indexe zur Bereitstellung der Abfrage verwendet werden können. Für eine ORDER BY a ASC, b ASC-Abfrage ist beispielsweise ein zusammengesetzter Index für die a ASC, b ASC-Felder erforderlich.

Optimieren Sie die Leistung und Kosten von Cloud Firestore-Abfragen, indem Sie die Reihenfolge der Felder im Index optimieren. Achten Sie dabei darauf, dass der Index von links nach rechts sortiert ist, damit die Abfrage zu einem Datensatz führt, der das Scannen unnötiger Indexeinträge verhindert.

Angenommen, Sie möchten in einer Sammlung von Mitarbeitern nach Mitarbeitern in den USA suchen, deren Gehalt über 100.000 $ liegt und deren Berufserfahrung mehr als 0 Jahre beträgt. Aus Ihrer Kenntnis des Datensatzes wissen Sie, dass die Gehaltsbeschränkung selektiver ist als die Erfahrungsbeschränkung. Der ideale Index, der die Anzahl der Indexscans reduzieren würde, wäre (salary [...], experience [...]). Eine schnelle und kosteneffiziente Abfrage würde also salary vor experience sortieren und so aussehen:

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 Practices für die Optimierung von Indexen

Beachten Sie beim Optimieren von Indexen die folgenden Best Practices.

Indexfelder nach Gleichheitsbedingungen sortieren, gefolgt vom selektivsten Bereichs- oder Ungleichheitsfeld

Bei Cloud Firestore werden die Felder links im zusammengesetzten Index verwendet, um die Gleichheitsbeschränkungen und gegebenenfalls die Bereichs- oder Ungleichheitsbeschränkung für das erste Feld der orderBy()-Abfrage zu erfüllen. Durch diese Einschränkungen kann die Anzahl der Indexeinträge, die von Cloud Firestore gescannt werden, reduziert werden. Cloud Firestore verwendet die verbleibenden Felder des Index, um andere Bereichs- oder Ungleichheitseinschränkungen der Abfrage zu erfüllen. Durch diese Einschränkungen wird nicht die Anzahl der Indexeinträge reduziert, die von Cloud Firestore gescannt werden, sondern nicht übereinstimmende Dokumente werden herausgefiltert, sodass die Anzahl der an die Clients zurückgegebenen Dokumente reduziert wird.

Weitere Informationen zum Erstellen effizienter Indexe finden Sie unter Indexeigenschaften.

Felder in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortieren

Damit Cloud Firestore den optimalen Index für Ihre Abfrage auswählt, geben Sie eine orderBy()-Klausel an, die Felder in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortiert. Eine höhere Selektivität entspricht einer kleineren Teilmenge von Dokumenten, während eine niedrigere Selektivität einer größeren Teilmenge von Dokumenten entspricht. Achten Sie darauf, dass Sie Bereichs- oder Ungleichheitsfelder mit höherer Selektivität früher in der Indexsortierung auswählen als Felder mit niedrigerer Selektivität.

Um die Anzahl der Dokumente zu minimieren, die von Cloud Firestore im Netzwerk gescannt und zurückgegeben werden, sollten Sie Felder immer in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung sortieren. Wenn die Ergebnismenge nicht in der erforderlichen Reihenfolge liegt und die Ergebnismenge erwartungsgemäß klein ist, können Sie eine clientseitige Logik implementieren, um sie entsprechend Ihren Bestellerwartungen neu zu ordnen.

Angenommen, Sie möchten in einer Gruppe von Mitarbeitern nach Mitarbeitern in den USA suchen, deren Gehalt über 100.000 $ liegt, und die Ergebnisse nach der Berufserfahrung des Mitarbeiters sortieren. Wenn Sie davon ausgehen, dass nur eine kleine Anzahl von Mitarbeitern ein Gehalt von über 100.000 $ hat, ist die folgende Abfrage am effizientesten:

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`

Wenn Sie der Abfrage eine Sortierung nach experience hinzufügen, erhalten Sie zwar dieselben Dokumente und müssen die Ergebnisse nicht auf den Clients neu sortieren, aber die Abfrage liest möglicherweise viel mehr irrelevante Indexeinträge als die vorherige Abfrage. Das liegt daran, dass Cloud Firestore immer einen Index bevorzugt, dessen Indexfeldpräfix mit der ORDER BY-Klausel der Abfrage übereinstimmt. Wenn experience in die Klausel „Order by“ aufgenommen wurde, wählt Cloud Firestore den Index (experience [...], salary [...]) zum Berechnen der Abfrageergebnisse aus. Da für experience keine anderen Einschränkungen gelten, werden in Cloud Firestore alle Indexeinträge der Sammlung employees gelesen, bevor der Filter salary angewendet wird, um die endgültige Ergebnismenge zu ermitteln. Das bedeutet, dass Indexeinträge, die den salary-Filter nicht erfüllen, trotzdem gelesen werden, was die Latenz und die Kosten der Abfrage erhöht.

Preise

Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder werden basierend auf den gelesenen Dokumenten und den gelesenen Indexeinträgen abgerechnet.

Weitere Informationen finden Sie auf der Seite Preise.

Beschränkungen

Neben den Einschränkungen für Abfragen gelten auch die folgenden Einschränkungen, wenn Sie Abfragen mit Bereichs- und Ungleichheitsfiltern für mehrere Felder verwenden:

  • Abfragen mit Bereichs- oder Ungleichheitsfiltern für Dokumentfelder und nur Gleichheitsbeschränkungen für den Dokumentschlüssel (__name__) werden nicht unterstützt.
  • Mit Cloud Firestore wird die Anzahl der Bereichs- oder Ungleichheitsfelder auf 10 begrenzt. Damit soll verhindert werden, dass die Ausführung von Abfragen zu teuer wird.

Nächste Schritte