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

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() , которое упорядочивает поля в порядке убывания селективности ограничений запроса. Более высокая селективность соответствует меньшему подмножеству документов, а более низкая — большему. Убедитесь, что поля диапазона или неравенства с более высокой селективностью выбираются раньше в порядке упорядочивания индекса, чем поля с более низкой селективностью.

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

Например, предположим, вы хотите выполнить поиск по группе сотрудников в США, чья зарплата превышает 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. Это сделано для того, чтобы запросы не стали слишком ресурсоемкими в выполнении.

Что дальше?