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

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

Что дальше?