Запрос с фильтрами диапазона и неравенства в обзоре нескольких полей

Cloud Firestore поддерживает использование фильтров диапазона и неравенства для нескольких полей в одном запросе. Вы можете применять условия диапазона и неравенства к нескольким полям и упростить разработку приложения, делегировав реализацию логики постобработки фильтра Cloud Firestore .

Фильтры диапазона и неравенства для нескольких полей

Приведенный ниже запрос использует диапазонные фильтры по численности населения и плотности, чтобы вернуть все города, где численность населения превышает 1 000 000 человек, а плотность населения составляет менее 10 000 человек на единицу площади.

Веб-версия 9 модульная

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

Быстрый

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)

Идти

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

Руби

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

Единство

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

Дарт

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

Вопросы индексирования

Прежде чем выполнять запросы, ознакомьтесь с информацией о запросах и модели данных Cloud Firestore .

В Cloud Firestore предложение ORDER BY в запросе определяет, какие индексы могут быть использованы для обработки запроса. Например, запрос ORDER BY a ASC, b ASC требует составного индекса по полям a ASC, b ASC .

Для оптимизации производительности и стоимости запросов к Cloud Firestore оптимизируйте порядок полей в индексе. Для этого убедитесь, что индекс упорядочен слева направо таким образом, чтобы запрос сводился к набору данных, предотвращающему сканирование ненужных записей индекса.

Предположим, вы хотите выполнить поиск по набору данных о сотрудниках и найти сотрудников из США, чья зарплата превышает 100 000 долларов, а стаж работы — 0 лет. Исходя из вашего понимания набора данных, вы знаете, что ограничение по зарплате более избирательно, чем ограничение по стажу работы. Идеальным индексом, который бы сократил количество сканирований индекса, был бы (salary [...], experience [...]) . Таким образом, быстрый и экономичный запрос должен был бы упорядочивать salary перед experience и выглядеть следующим образом:

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

Передовые методы оптимизации индексов

При оптимизации индексов следует учитывать следующие рекомендации.

Упорядочить поля индекса по равенствам, а затем по наиболее избирательному диапазону или полю неравенства.

Cloud Firestore использует самые левые поля составного индекса для удовлетворения ограничений равенства и ограничений диапазона или неравенства, если таковые имеются, для первого поля запроса orderBy() . Эти ограничения могут уменьшить количество записей индекса, которые сканирует Cloud Firestore . Cloud Firestore использует оставшиеся поля индекса для удовлетворения других ограничений диапазона или неравенства запроса. Эти ограничения не уменьшают количество записей индекса, которые сканирует Cloud Firestore , но отфильтровывают несовпадающие документы, так что количество документов, возвращаемых клиентам, уменьшается.

Для получения более подробной информации о создании эффективных индексов см. раздел «Свойства индекса» .

Упорядочить поля в порядке убывания селективности ограничений запроса

Чтобы гарантировать, что Cloud Firestore выберет оптимальный индекс для вашего запроса, укажите условие orderBy() , которое упорядочивает поля в порядке убывания селективности ограничений запроса. Более высокая селективность соответствует меньшему подмножеству документов, а более низкая — большему. Убедитесь, что поля диапазона или неравенства с более высокой селективностью выбираются раньше в порядке упорядочивания индекса, чем поля с более низкой селективностью.

To minimize the number of documents that Cloud Firestore scans and returns over the network, you should always order fields in the decreasing order of query constraint selectivity. If the result set is not in the required order and the result set is expected to be small, you can implement client-side logic to reorder it as per your ordering expectation.

Например, предположим, вы хотите выполнить поиск по группе сотрудников в США, чья зарплата превышает 100 000 долларов, и отсортировать результаты по стажу работы сотрудника. Если вы ожидаете, что лишь небольшое количество сотрудников будет иметь зарплату выше 100 000 долларов, то наиболее эффективный способ сформулировать запрос будет следующим:

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`

Добавление параметра сортировки по experience к запросу даст тот же набор документов и позволит избежать повторной сортировки результатов на стороне клиента, однако запрос может прочитать гораздо больше лишних записей индекса, чем предыдущий запрос. Это связано с тем, что Cloud Firestore всегда предпочитает индекс, префикс полей которого соответствует предложению ORDER BY запроса. Если в предложение ORDER BY добавить параметр experience , Cloud Firestore выберет индекс (experience [...], salary [...]) для вычисления результатов запроса. Поскольку других ограничений на experience нет, Cloud Firestore прочитает все записи индекса коллекции employees , прежде чем применить фильтр salary для получения окончательного набора результатов. Это означает, что записи индекса, не удовлетворяющие фильтру salary , все равно будут прочитаны, что увеличит задержку и стоимость запроса.

Цены

Запросы с фильтрами по диапазону и неравенству по нескольким полям оплачиваются исходя из количества прочитанных документов и прочитанных записей в индексе.

Подробную информацию см. на странице «Цены» .

Ограничения

Помимо ограничений, связанных с самими запросами , перед использованием запросов с фильтрами по диапазону и неравенству по нескольким полям следует учитывать следующие ограничения:

  • Запросы с фильтрами по диапазону или неравенству по полям документа и только ограничениями равенства по ключу документа (__name__) не поддерживаются.
  • Cloud Firestore ограничивает количество полей диапазона или неравенства до 10. Это сделано для того, чтобы запросы не стали слишком ресурсоемкими в выполнении.

Что дальше?