Описание
Определите временные переменные, на которые можно будет ссылаться на последующих этапах конвейера.
Переменные, созданные на этапе let(...) не включаются в окончательные результаты, если они явно не присвоены полю на более позднем этапе (например, с помощью add_fields(...) или select(...) ). Это позволяет упростить сложную логику, разбив ее на более мелкие, многократно используемые компоненты, не загромождая выходные документы. Этап let(...) особенно полезен для коррелированных подконвейеров , где подконвейеру необходимо ссылаться на значение из области видимости родительского документа.
Примеры
Node.js
const results = await db.pipeline()
.collection("/awards")
// `let(...)` referred to as `define(...)` in the Web SDK.
.define(rand().as("r"))
.addFields(
switchOn(
lessThan(variable("r"), 0.05), constant("rare"),
lessThan(variable("r"), 0.25), constant("uncommon"),
constant("common")).as("random_score"))
.execute();
Поведение
Переменные против полей
В то время как поля представляют собой данные, хранящиеся в документах, переменные — это временные значения, существующие только во время выполнения конвейера обработки данных.
| Поля | Переменные | |
|---|---|---|
| Цель | получать доступ к полям или сохранять их в документах. | генерировать или получать доступ к временным значениям во время выполнения конвейера |
| Использование SDK | field("name") | variable("name") |
| Объем | локальный к текущему документу | от глобального уровня до трубопроводов и подтрубопроводов |
| Неопределенные ссылки | оценивается как absent | генерирует ошибку во время выполнения |
Объем:
В то время как поля ограничены областью видимости локального документа, переменные определяются в отдельной области видимости и остаются доступными на разных этапах до первого появления этапа, который «объединяет» несколько документов (например, aggregate(...) или distinct(...) ). Этапы, которые «объединяют» несколько документов, не позволяют использовать ссылки на переменные впоследствии, поскольку при объединении результатов предыдущего этапа больше нет одного значения для переменной.
Выполните следующие действия : Укажите ссылку на переменную после фильтрации полей документа.
Node.js
const results = db.pipeline()
.collection("/awards")
.define(min(field("score").abs(), constant(100)).as("normalized_score"))
.select(field("__name__"), field("owner_id"))
// Successfully able to use the variable.
.where(variable("normalized_score").greaterThan(10))
.execute();
Не следует : ссылаться на переменную после выполнения агрегации.
Node.js
const results = db.pipeline()
.collection("/awards")
.define(min(field("score").abs(), constant(100)).as("normalized_score"))
.aggregate({
accumulators: [ field("score").avg().as("avg_score") ],
groups: [ field("owner_id") ]
})
// Attempting to use the variable throws a request validation error.
.where(variable("normalized_score").greaterThan(10))
.execute();
Неопределенные ссылки:
Хотя обращение к неопределенному полю допустимо (и просто возвращает " absent "), попытка обратиться к неопределенной переменной завершится ошибкой во время проверки запроса. В этом смысле ссылки на поля можно рассматривать как поиск в карте во время выполнения, в то время как ссылки на переменные больше похожи на переменные в статически компилируемом языке программирования.
Глобальная область действия и подзапросы
Переменные необходимы при работе с вложенными конвейерами. Подконвейер выполняется в собственной области видимости и может получать доступ только к полям документов, которые он обрабатывает в данный момент. Чтобы использовать значение из «родительского» документа внутри подзапроса, необходимо сначала определить его как переменную, используя этап let(...) .
Node.js
// Fetch reviewers alongside their negative reviews.
const pipeline = db.pipeline()
.collection("/reviewers")
// `let(...)` referred to as `define(...)` in the Web SDK.
.define(field("__name__").as("reviewer_name"))
.select("__name__", array(db.pipeline().collectionGroup("reviews")
.where(field("author").equals(variable("reviewer_name")))
.where(field("rating").lessThan(2))
.select("review", "rating")).as("negative_reviews"))
.execute();
Перекрывающиеся переменные
Определение переменной с именем, которое уже было определено на предыдущем этапе let(...) перезапишет предыдущую переменную. Это можно использовать для обновления временного состояния по мере выполнения конвейера.
Переменные, на которые ссылаются в подконвейере, подчиняются правилам лексической области видимости , характерным для многих языков программирования, и ссылаются на переменные с тем же именем, определенные ближайшим (родительским) конвейером.
Сравнение с add_fields(...)
Этап let(...) ведет себя аналогично этапу add_fields(...) , но вместо добавления полей в документ он присваивает значения переменным.