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

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)

Ява

db.collection("cities")
  .whereGreaterThan("population", 1000000)
  .whereLessThan("density", 10000);

Node.js

db.collection("cities")
  .where('population', '>', 1000000),
  .where('density', '<', 10000)

Питон

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

С#

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)

С++

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 и будет выглядеть следующим образом:

Ява

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

Питон

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 долларов, то наиболее эффективный способ составления запроса будет следующим:

Ява

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`

Питон

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

Что дальше?