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

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

Ява Андроид

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

Что дальше?