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

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

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

Прежде чем запускать запросы, ознакомьтесь с [запросами][1] и [моделью данных][2] Cloud Firestore .

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

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

Suppose you want to search through a collection of employees and find United States employees whose salary is more than $100,000 and whose number of years of experience is greater than 0. Based on your understanding of the dataset, you know that the salary constraint is more selective than the experience constraint. The ideal index that would reduce the number of index scans would be the (salary [...], experience [...]) . Thus, the query that would be fast and cost-efficient would order salary before experience and look as follows:

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 uses the leftmost fields of a composite index to satisfy the equality constraints and the range or inequality constraint, if any, on the first field of the orderBy() query. These constraints can reduce the number of index entries that Cloud Firestore scans. Cloud Firestore uses the remaining fields of the index to satisfy other range or inequality constraints of the query. These constraints don't reduce the number of index entries that Cloud Firestore scans but filter out unmatched documents so that the number of documents that are returned to the clients are reduced.

Для получения дополнительной информации о создании эффективных индексов см. [свойства индекса][4].

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

To ensure that Cloud Firestore selects the optimal index for your query, specify an orderBy() clause that orders fields in decreasing order of query constraint selectivity. Higher selectivity matches a smaller subset of documents, while lower selectivity matches a larger subset of documents. Ensure that you select range or inequality fields with higher selectivity earlier in the index ordering than fields with lower selectivity.

Чтобы минимизировать количество документов, которые 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`

While adding an ordering on experience to the query will yield the same set of documents and obviate re-ordering the results on the clients, the query may read many more extraneous index entries than the earlier query. This is because Cloud Firestore always prefers an index whose index fields prefix match the order by clause of the query. If experience were added to the order by clause, then Cloud Firestore will select the (experience [...], salary [...]) index for computing query results. Since there are no other constraints on experience , Cloud Firestore will read all index entries of the employees collection before applying the salary filter to find the final result set. This means that index entries which don't satisfy the salary filter are still read, thus increasing the latency and cost of the query.

Цены

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

Подробную информацию см. на странице [Цены][5].

Ограничения

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

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

Что дальше?

  • Узнайте об [оптимизации ваших запросов][3].
  • Узнайте больше о [выполнении простых и составных запросов][8].
  • Разберитесь, как [ Cloud Firestore использует индексы][9].

[1]: /docs/firestore/query-data/get-data [2]: /docs/firestore/data-model [3]: /docs/firestore/query-data/multiple-range-optimize-indexes [4]: /docs/firestore/concepts/index-overview#index_properties [5]: /docs/firestore/pricing [6]: /docs/firestore/query-data/queries#query_limitations [7]: https://en.wikipedia.org/wiki/Disjunctive_normal_form [8]: /docs/firestore/query-data/queries [9]: /docs/firestore/concepts/index-overview [10]: /docs/firestore/query-data/multiple-range-optimize-indexes