Übersicht: Abfrage mit Bereichs- und Ungleichheitsfiltern für mehrere Felder

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

Bereichs- und Ungleichheitsfilter für mehrere Felder

Die folgende Abfrage gibt alle Nutzer zurück, deren Alter größer als 35 und deren Größe zwischen 60 und 70 liegt. Dazu werden Bereichsfilter für Alter und Größe verwendet.

Web version 9 modular

  const q = query(
      collection(db, "users"),
      where('age', '>', 35),
      where('height', '>', 60),
      where('height', '<', 70)
    );

Swift

 let query = db.collection("users")
   .whereField("age", isGreaterThan: 35)
   .whereField("height", isGreaterThan: 60)
   .whereField("height", isLessThan: 70)

Objective-C

 FIRQuery *query =
  [[[[self.db collectionWithPath:@"users"]
 queryWhereField:@"age" isGreaterThan:@35]
    queryWhereField:@"height" isGreaterThan:@60]
        queryWhereField:@"height" isLessThan:@70];

Java-Android

 Query query = db.collection("users")
  .whereGreaterThan("age", 35)
  .whereGreaterThan("height", 60)
  .whereLessThan("height", 70);

Kotlin+KTX für Android

 val query = db.collection("users")
  .whereGreaterThan("age", 35)
  .whereGreaterThan("height", 60)
  .whereLessThan("height", 70)

Java

  db.collection("users")
    .whereGreaterThan("age", 35)
    .whereGreaterThan("height", 60)
    .whereLessThan("height", 70);

Node.js

db.collection("users")
  .where('age', '>', 35),
  .where('height', '>', 60),
  .where('height', '<', 70)

Hinweise zur Indexierung

Bevor Sie mit dem Ausführen von Abfragen beginnen, sollten Sie die Informationen zu Abfragen und zum Firestore-Datenmodell lesen.

In Firestore bestimmt die ORDER BY-Klausel einer Abfrage, welche Indexe zum Bereitstellen der Abfrage verwendet werden können. Eine ORDER BY a ASC, b ASC-Abfrage erfordert beispielsweise einen zusammengesetzten Index für die a ASC, b ASC-Felder.

Zur Optimierung der Leistung und Kosten von Firestore-Abfragen sollten Sie die Reihenfolge der Felder im Index optimieren. Dazu müssen Sie dafür sorgen, dass der Index von links nach rechts so geordnet ist, dass die Abfrage in ein Dataset umgewandelt wird, das das Scannen irrelevanter Indexeinträge verhindert.

Angenommen, Sie möchten eine Sammlung von Mitarbeitern durchsuchen und Mitarbeiter finden, deren Gehalt mehr als 100.000 beträgt und deren Berufserfahrung größer als 0 ist. Nach Ihrem Verständnis des Datasets wissen Sie, dass die Gehaltsbeschränkung selektiver ist als die Erfahrungsbeschränkung. Der ideale Index, der die Anzahl der Indexscans reduzieren würde, ist (salary [...], experience [...]). Somit würde die schnelle und kostengünstige Abfrage salary vor experience bestellen 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 zum Optimieren von Indexen

Beachten Sie beim Optimieren von Indexen die folgenden Best Practices.

Indexfelder nach Gleichheiten sortieren, gefolgt vom selektiven Bereich oder Ungleichheitsfeld

Firestore verwendet die Felder ganz links eines zusammengesetzten Index, um die Gleichheitseinschränkungen und die Bereichs- oder Ungleichheitseinschränkung, falls vorhanden, für das erste Feld der Abfrage orderBy() zu erfüllen. Diese Einschränkungen können die Anzahl der Indexeinträge verringern, die Firestore scannt. Firestore verwendet die verbleibenden Felder des Index, um andere Bereichs- oder Ungleichheitseinschränkungen der Abfrage zu erfüllen. Diese Einschränkungen reduzieren nicht die Anzahl der Indexeinträge, die Firestore scannt, sondern filtert nicht übereinstimmende Dokumente heraus, sodass die Anzahl der Dokumente, die an die Clients zurückgegeben werden, reduziert wird.

Weitere Informationen zum Erstellen effizienter Indexe finden Sie unter Definition eines perfekten Index.

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

Damit Firestore den optimalen Index für Ihre Abfrage auswählt, geben Sie eine orderBy()-Klausel an. Diese ordnet Felder in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung. 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 Indexreihenfolge auswählen als Felder mit geringerer Selektivität.

Um die Anzahl der Dokumente zu minimieren, die Firestore scannt und über das Netzwerk zurückgibt, sollten Sie Felder immer in absteigender Reihenfolge der Selektivität der Abfrageeinschränkung anordnen. Wenn die Ergebnismenge nicht in der erforderlichen Reihenfolge vorliegt und die Ergebnismenge voraussichtlich klein ist, können Sie clientseitige Logik implementieren, um sie entsprechend Ihren Erwartungen in Bezug auf die Reihenfolge neu anzuordnen.

Angenommen, Sie möchten in einer Sammlung von Mitarbeitenden nach Mitarbeitenden mit einem Gehalt von mehr als 100.000 suchen und die Ergebnisse nach dem Jahr der Erfahrung des Mitarbeiters sortieren. Wenn Sie davon ausgehen, dass nur eine geringe Anzahl von Mitarbeitenden ein Gehalt von mehr als 100.000 Mitarbeitern haben wird, können Sie die Abfrage so am effizientesten schreiben:

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`

Während das Hinzufügen einer Sortierung in experience zur Abfrage den gleichen Satz von Dokumenten liefert und die Neuanordnung der Ergebnisse auf den Clients vermieden wird, kann die Abfrage viel mehr irrelevante Indexeinträge lesen als die vorherige Abfrage. Dies liegt daran, dass Firestore immer einen Index bevorzugt, dessen Indexfeldpräfix der Sortierklausel nach der Abfrage entsprechen. Wenn experience zur Klausel „order by“ hinzugefügt wurde, wählt Firestore den Index (experience [...], salary [...]) zur Berechnung der Abfrageergebnisse aus. Da es für experience keine anderen Einschränkungen gibt, liest Firestore alle Indexeinträge der Sammlung employees, bevor der Filter salary angewendet wird, um den endgültigen Ergebnissatz zu finden. Das bedeutet, dass Indexeinträge, die den Filter salary nicht erfüllen, dennoch gelesen werden, wodurch sich die Latenz und die Kosten der Abfrage erhöhen.

Preise

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

Ausführliche Informationen finden Sie in der Preisübersicht.

Beschränkungen

Beachten Sie neben den Abfrageeinschränkungen die folgenden Einschränkungen, bevor 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.
  • Firestore begrenzt die Anzahl der Bereichs- oder Ungleichheitsfelder auf 10. Dies soll verhindern, dass Abfragen zu teuer für die Ausführung werden.

Weitere Informationen