Общая информация
Операции конвейера предоставляют новый интерфейс запросов для Cloud Firestore, который поддерживает расширенные функции запросов и сложные выражения. В нем появилось много новых функций, включая min(...), max(...), substring(...), regex_match(...) и array_contains_all(...), а также этапы, позволяющие выполнять сложные преобразования.
Начало работы
Чтобы установить и инициализировать клиентские SDK, следуйте инструкциям в следующих руководствах:
- Подробнее о том, как начать работу с SDK для мобильных приложений и сайтов…
- Начало работы с серверными клиентскими библиотеками.
Синтаксис
В следующих разделах приведены общие сведения о синтаксисе операций в конвейере.
Основные понятия
Одно из заметных отличий операций конвейера – введение явного упорядочивания этапов. Это позволяет выражать более сложные запросы. Однако это заметное отклонение от существующего интерфейса запросов, использующего основные операции, в которых порядок этапов подразумевался. Рассмотрим следующий пример операций конвейера:
Web
const pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the // pipeline would have unintentional results. .limit(10);
Swift
let pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(Field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort([Field("name").ascending()]) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Kotlin
val pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Java
Pipeline pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10);
Python
from google.cloud.firestore_v1.pipeline_expressions import Field pipeline = ( client.pipeline() .collection("cities") .where(Field.of("population").greater_than(100_000)) .sort(Field.of("name").ascending()) .limit(10) )
Проложить маршрут
pipeline := client.Pipeline(). Collection("cities"). Where(firestore.FieldOf("population").GreaterThan(100000)). Sort(firestore.Orders(firestore.Ascending(firestore.FieldOf("name")))). Limit(10)
Инициализация
Операции конвейера имеют очень знакомый синтаксис, заимствованный из существующих запросов Cloud Firestore. Для начала вы инициализируете запрос, написав следующее:
Web
const { getFirestore } = require("firebase/firestore"); const { execute } = require("firebase/firestore/pipelines"); const database = getFirestore(app, "enterprise"); const pipeline = database.pipeline();
Swift
let firestore = Firestore.firestore(database: "enterprise") let pipeline = firestore.pipeline()
Kotlin
val firestore = Firebase.firestore("enterprise") val pipeline = firestore.pipeline()
Java
FirebaseFirestore firestore = FirebaseFirestore.getInstance("enterprise"); PipelineSource pipeline = firestore.pipeline();
Python
firestore_client = firestore.client(default_app, "your-new-enterprise-database") pipeline = firestore_client.pipeline()
Проложить маршрут
client, err := firestore.NewClientWithDatabase(ctx, projectID, databaseID) if err != nil { fmt.Fprintf(w, "firestore.NewClientWithDatabase failed: %v", err) return err } defer client.Close() pipeline := client.Pipeline().Collection("books")
Структура
При создании операций конвейера важно понимать несколько терминов: этапы, выражения, функции и оболочки подзапросов.

Этапы. Конвейер может состоять из одного или нескольких этапов. Логически они представляют собой последовательность шагов (или этапов), выполняемых для обработки запроса.
Выражения. Этапы часто принимают выражения, позволяющие выражать более сложные запросы. Выражение может быть простым и состоять из одной функции, например eq("a", 1). Вы также можете создавать более сложные выражения, вкладывая их друг в друга, например and(eq("a", 1), eq("b", 2))..
Оболочки подзапросов. Такие функции, как array() и scalar(), позволяют встраивать вложенный конвейер в качестве выражения на этапе.
Поля, константы и переменные
Операции конвейера поддерживают сложные выражения. Поэтому важно различать, что представляет собой значение: поле, константу или переменную.
Поля относятся к данным в документах, а константы позволяют указывать любое значение в качестве аргумента выражения. Переменные позволяют определять и использовать временные значения, которые относятся к выполнению запроса, а не к обрабатываемым документам. Ниже приведен обзор этих концепций. Дополнительную информацию о том, как читать и записывать переменные во время выполнения запроса, можно найти в разделе let(...).
| Поля | Константы | Переменные | |
|---|---|---|---|
| Purpose | получать доступ к полям в документах или сохранять их; | указать фиксированное значение; | использовать временные значения во время выполнения конвейера |
| Использование SDK | field("name") |
constant("val") |
variable("name") |
| Область действия | локально для текущего документа | глобальный | глобальные для конвейера и подконвейеров; |
| Undefined Reference | вычисляется как absent |
Н/Д | вызывает ошибку выполнения |
Примеры
Web
const pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Swift
let pipeline = db.pipeline() .collection("cities") .where(Field("name").equal(Constant("Toronto")))
Kotlin
val pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")))
Java
Pipeline pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Python
from google.cloud.firestore_v1.pipeline_expressions import Field, Constant pipeline = ( client.pipeline() .collection("cities") .where(Field.of("name").equal(Constant.of("Toronto"))) )
Проложить маршрут
pipeline := client.Pipeline().Collection("cities"). Where(firestore.FieldOf("name").Equal(firestore.ConstantOf("Toronto")))
Этапы
Этапы ввода
Этап ввода – это первый этап запроса. Он определяет начальный набор документов, по которым вы выполняете запрос. Для операций Pipeline это в основном похоже на существующие запросы, где большинство запросов начинается с этапа collection(...) или collection_group(...). Два новых этапа ввода – database() и documents(...). database() позволяет возвращать все документы в базе данных, а documents(...) действует так же, как пакетное чтение.
Web
let results; // Return all restaurants in San Francisco results = await execute(db.pipeline().collection("cities/sf/restaurants")); // Return all restaurants results = await execute(db.pipeline().collectionGroup("restaurants")); // Return all documents across all collections in the database (the entire database) results = await execute(db.pipeline().database()); // Batch read of 3 documents results = await execute(db.pipeline().documents([ doc(db, "cities", "SF"), doc(db, "cities", "DC"), doc(db, "cities", "NY") ]));
Swift
var results: Pipeline.Snapshot // Return all restaurants in San Francisco results = try await db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = try await db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = try await db.pipeline().database().execute() // Batch read of 3 documents results = try await db.pipeline().documents([ db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ]).execute()
Kotlin
var results: Task<Pipeline.Snapshot> // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute() // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute()
Java
Task<Pipeline.Snapshot> results; // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute(); // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute(); // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute(); // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute();
Python
# Return all restaurants in San Francisco results = client.pipeline().collection("cities/sf/restaurants").execute() # Return all restaurants results = client.pipeline().collection_group("restaurants").execute() # Return all documents across all collections in the database (the entire database) results = client.pipeline().database().execute() # Batch read of 3 documents results = ( client.pipeline() .documents( client.collection("cities").document("SF"), client.collection("cities").document("DC"), client.collection("cities").document("NY"), ) .execute() )
Проложить маршрут
// Return all restaurants in San Francisco results1, err := client.Pipeline().Collection("cities/sf/restaurants").Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Return all restaurants results2, err := client.Pipeline().CollectionGroup("restaurants").Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Return all documents across all collections in the database (the entire database) results3, err := client.Pipeline().Database().Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Batch read of 3 documents results4, err := client.Pipeline(). Documents([]*firestore.DocumentRef{ client.Collection("cities").Doc("SF"), client.Collection("cities").Doc("DC"), client.Collection("cities").Doc("NY"), }). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Как и на всех остальных этапах, порядок результатов на этих этапах ввода нестабилен. Если вам нужен определенный порядок, всегда добавляйте оператор sort(...).
Место
Этап where(...) действует как стандартная операция фильтрации документов, созданных на предыдущем этапе, и в основном повторяет существующий синтаксис "where" для существующих запросов. Документы, для которых выражение возвращает значение, отличное от true, исключаются из результатов.
Можно объединить несколько операторов where(...), чтобы они действовали как выражение and(...). Например, два следующих запроса логически эквивалентны и взаимозаменяемы:
Web
let results; results = await execute(db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) ); results = await execute(db.pipeline().collection("books") .where(and(field("rating").equal(5), field("published").lessThan(1900))) );
Swift
var results: Pipeline.Snapshot results = try await db.pipeline().collection("books") .where(Field("rating").equal(5)) .where(Field("published").lessThan(1900)) .execute() results = try await db.pipeline().collection("books") .where(Field("rating").equal(5) && Field("published").lessThan(1900)) .execute()
Kotlin
var results: Task<Pipeline.Snapshot> results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute() results = db.pipeline().collection("books") .where(Expression.and(field("rating").equal(5), field("published").lessThan(1900))) .execute()
Java
Task<Pipeline.Snapshot> results; results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute(); results = db.pipeline().collection("books") .where(Expression.and( field("rating").equal(5), field("published").lessThan(1900) )) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import And, Field results = ( client.pipeline() .collection("books") .where(Field.of("rating").equal(5)) .where(Field.of("published").less_than(1900)) .execute() ) results = ( client.pipeline() .collection("books") .where(And(Field.of("rating").equal(5), Field.of("published").less_than(1900))) .execute() )
Проложить маршрут
results1, err := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("rating").Equal(5)). Where(firestore.FieldOf("published").LessThan(1900)). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } results2, err := client.Pipeline(). Collection("books"). Where(firestore.And( firestore.FieldOf("rating").Equal(5), firestore.FieldOf("published").LessThan(1900), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Выбрать / добавить и удалить поля
select(...), add_fields(...) и remove_fields(...) позволяют изменять поля, возвращаемые на предыдущем этапе. Эти три типа обычно называют
сценами проекционного типа.
Операторы select(...) и add_fields(...) позволяют указать результат выражения для названия поля, заданного пользователем. select(...) возвращает только документы с указанными названиями полей, а add_fields(...) расширяет схему предыдущего этапа (потенциально перезаписывая значения с идентичными названиями полей).
remove_fields(...) позволяет указать набор полей, которые нужно удалить из предыдущего этапа. Если указать несуществующие названия полей, ничего не произойдет.
Подробнее об этом рассказывается в разделе Ограничение возвращаемых полей ниже. В целом использование такого этапа для ограничения результата только полями, необходимыми клиенту, помогает снизить стоимость и задержку для большинства запросов.
Агрегированные / отдельные
Этап aggregate(...) позволяет выполнить ряд агрегирований по входным документам. По умолчанию все документы агрегируются вместе, но можно указать необязательный аргумент grouping, чтобы агрегировать входные документы в разные сегменты.
Web
const results = await execute(db.pipeline() .collection("books") .aggregate( field("rating").average().as("avg_rating") ) .distinct(field("genre")) );
Swift
let results = try await db.pipeline() .collection("books") .aggregate([ Field("rating").average().as("avg_rating") ], groups: [ Field("genre") ]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .aggregate( AggregateStage .withAccumulators(AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre")) ) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .aggregate(AggregateStage .withAccumulators( AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre"))) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .aggregate( Field.of("rating").average().as_("avg_rating"), groups=[Field.of("genre")] ) .execute() )
Проложить маршрут
snapshot := client.Pipeline(). Collection("books"). Aggregate( firestore.Accumulators(firestore.Average("rating").As("avg_rating")), firestore.WithAggregateGroups("genre"), ). Execute(ctx)
Если параметр groupings не указан, на этом этапе будет создан только один документ, в противном случае документ будет создан для каждой уникальной комбинации значений groupings.
Этап distinct(...) – это упрощенный оператор агрегирования, который позволяет генерировать только уникальные значения groupings без каких-либо аккумуляторов. Во всех остальных отношениях он ведет себя так же, как и aggregate(...). В примере ниже показано:
Web
const results = await execute(db.pipeline() .collection("books") .distinct( field("author").toUpper().as("author"), field("genre") ) );
Swift
let results = try await db.pipeline() .collection("books") .distinct([ Field("author").toUpper().as("author"), Field("genre") ]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .distinct(Field.of("author").to_upper().as_("author"), "genre") .execute() )
Проложить маршрут
snapshot := client.Pipeline(). Collection("books"). Distinct(firestore.Fields( firestore.ToUpper(firestore.FieldOf("author")).As("author"), firestore.FieldOf("genre"), )). Execute(ctx)
Functions
Функции – это строительные блоки для создания выражений и сложных запросов. Полный список функций с примерами приведен в справочнике по функциям. Напомним, как выглядит типичный запрос:

Многие этапы принимают выражения, содержащие одну или несколько функций. Чаще всего функции используются на этапах where(...) и select(...). Существует два основных типа
функций, с которыми вы должны быть знакомы:
Web
let results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = await execute(db.pipeline().collection("books") .select(field("current").logicalMinimum(field("updated")).as("price_min")) ); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = await execute(db.pipeline().collection("books") .aggregate(field("price").minimum().as("min_price")) );
Swift
var results: Pipeline.Snapshot // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = try await db.pipeline().collection("books") .select([ Field("current").logicalMinimum(["updated"]).as("price_min") ]) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = try await db.pipeline().collection("books") .aggregate([Field("price").minimum().as("min_price")]) .execute()
Kotlin
var results: Task<Pipeline.Snapshot> // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute()
Java
Task<Pipeline.Snapshot> results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute(); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field # Type 1: Scalar (for use in non-aggregation stages) # Example: Return the min store price for each book. results = ( client.pipeline() .collection("books") .select( Field.of("current").logical_minimum(Field.of("updated")).as_("price_min") ) .execute() ) # Type 2: Aggregation (for use in aggregate stages) # Example: Return the min price of all books. results = ( client.pipeline() .collection("books") .aggregate(Field.of("price").minimum().as_("min_price")) .execute() )
Проложить маршрут
// Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results1, err := client.Pipeline(). Collection("books"). Select(firestore.Fields( firestore.LogicalMinimum(firestore.FieldOf("current"), firestore.FieldOf("updated")).As("price_min"), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err } // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results2, err := client.Pipeline(). Collection("books"). Aggregate(firestore.Accumulators( firestore.Minimum("price").As("min_price"), )). Execute(ctx).Results().GetAll() if err != nil { fmt.Fprintf(w, "GetAll failed: %v", err) return err }
Ограничения
В большинстве случаев версия Enterprise не накладывает ограничений на форму запроса. Другими словами, вы не ограничены небольшим количеством значений в запросе IN или OR. Вместо этого есть два основных ограничения, о которых вам следует знать:
- Срок: 60 секунд (как и в версии Standard).
- Использование памяти. Объем материализованных данных при выполнении запроса не должен превышать 128 МиБ.
Ошибки
Запросы могут не выполняться по разным причинам. Ниже приведены ссылки на распространенные ошибки и способы их устранения.
| Код ошибки | Действие |
DEADLINE_EXCEEDED
|
Выполняемый запрос превышает 60-секундный срок и требует дополнительной оптимизации. Советы вы найдете в разделе "Эффективность". Если вы не можете определить основную причину проблемы, обратитесь к команде. |
RESOURCE_EXHAUSTED
|
Выполняемый запрос превышает лимиты памяти и требует дополнительной оптимизации. Советы вы найдете в разделе "Эффективность". Если вы не можете определить основную причину проблемы, обратитесь к команде. |
INTERNAL
|
Свяжитесь с командой поддержки. |
Эффективность
В базах данных Enterprise Edition индекс не обязателен.
Это означает, что задержка при выполнении запроса может быть выше, чем при выполнении существующих запросов, которые просто не выполнялись и возвращали ошибку FAILED_PRECONDITION из-за отсутствия индекса. Чтобы повысить производительность операций конвейера,
вы можете предпринять несколько шагов.
Создание индексов
Используемый индекс
Объяснение запроса позволяет определить, обслуживается ли ваш запрос индексом или возвращается к менее эффективной операции, такой как сканирование таблицы. Если ваш запрос не полностью обслуживается из индекса, вы можете создать индекс, следуя инструкциям.
Создание индексов
Чтобы создать индексы, следуйте документации по управлению индексами. Прежде чем создавать индекс, ознакомьтесь с общими рекомендациями по работе с индексами в Cloud Firestore. Чтобы запрос мог использовать индексы, следуйте рекомендациям по созданию индексов с полями в следующем порядке:
- Все поля, которые будут использоваться в фильтрах равенства (в любом порядке).
- Все поля, по которым будет выполняться сортировка (в том же порядке).
- Поля, которые будут использоваться в фильтрах по диапазону или неравенству, в порядке убывания избирательности ограничений запроса.
Например, для следующего запроса:
Web
const results = await execute(db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("published").lessThan(1900)) .where(Field("genre").equal("Science Fiction")) .where(Field("rating").greaterThan(4.3)) .sort([Field("published").descending()]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("published").less_than(1900)) .where(Field.of("genre").equal("Science Fiction")) .where(Field.of("rating").greater_than(4.3)) .sort(Field.of("published").descending()) .execute() )
Проложить маршрут
snapshot := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("published").LessThan(1900)). Where(firestore.FieldOf("genre").Equal("Science Fiction")). Where(firestore.FieldOf("rating").GreaterThan(4.3)). Sort(firestore.Orders(firestore.Descending(firestore.FieldOf("published")))). Execute(ctx)
Рекомендуемый индекс – это индекс области действия коллекции в books для (genre [...], published DESC, avg_rating DESC)..
Плотность индекса
Cloud Firestore поддерживает разреженные и неразреженные индексы. Подробнее о плотности индекса…
Покрытые запросы и вторичные индексы
Cloud Firestore может не извлекать документ целиком, а просто возвращать результаты из индекса, если все возвращаемые поля присутствуют во вторичном индексе. Обычно это позволяет значительно снизить задержку и расходы. Используйте пример запроса ниже:
Web
const results = await execute(db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("category").like("%fantasy%")) .where(Field("title").exists()) .where(Field("author").exists()) .select([Field("title"), Field("author")]) .execute()
Kotlin
val results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute()
Java
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("category").like("%fantasy%")) .where(Field.of("title").exists()) .where(Field.of("author").exists()) .select("title", "author") .execute() )
Проложить маршрут
snapshot := client.Pipeline(). Collection("books"). Where(firestore.FieldOf("category").Like("%fantasy%")). Where(firestore.FieldOf("title").FieldExists()). Where(firestore.FieldOf("author").FieldExists()). Select(firestore.Fields("title", "author")). Execute(ctx)
Если в базе данных уже есть индекс области коллекции для books в (category [...], title [...], author [...]), то извлекать данные из основных документов не потребуется. В этом случае порядок в индексе не имеет значения, и для его обозначения используется [...].
Как ограничить возвращаемые поля
По умолчанию запрос Cloud Firestore возвращает все поля в документе, аналогично SELECT * в реляционных системах. Однако если вашему приложению нужен только поднабор полей, то для фильтрации на стороне сервера можно использовать этапы select(...) или restrict(...). Это позволит уменьшить размер ответа (снизив стоимость исходящего трафика) и сократить задержку.
Инструменты устранения неполадок
Объяснение запроса
Query Explain позволяет получить представление о показателях выполнения и сведения об используемых индексах.
Показатели
Операции конвейера полностью интегрированы с существующими показателями Cloud Firestore.
Ограничения и известные проблемы
Специализированные индексы
Операции конвейера пока не поддерживают существующие типы индексов array-contains и vector. Вместо того чтобы просто отклонять такие запросы, Cloud Firestore попытается использовать другие существующие индексы ascending и descending. Ожидается, что из-за этого выражения с array_contains или find_nearest будут работать медленнее, чем их существующие эквиваленты.
Поддержка в реальном времени и офлайн
Операции конвейера не поддерживают работу в режиме реального времени и офлайн.
Дальнейшие действия
- Изучите справочную документацию по функциям и этапам.
- Подробнее о том, как выполнять объединения с подзапросами…