Description
Définissez des variables temporaires auxquelles il est possible de faire référence dans les étapes ultérieures du pipeline.
Les variables créées à l'étape let(...) ne sont pas incluses dans les résultats finaux, sauf si elles sont explicitement attribuées à un champ lors d'une étape ultérieure (par exemple, à l'aide de add_fields(...) ou select(...)). Cela vous permet de simplifier la logique complexe en la divisant en composants plus petits et réutilisables, sans encombrer les documents de sortie. L'étape let(...) est particulièrement utile pour les sous-pipelines corrélés, où un sous-pipeline doit faire référence à une valeur de la portée du document parent.
Exemples
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();
Comportement
Variables et champs
Alors que les champs représentent les données stockées dans les documents, les variables sont des valeurs temporaires qui n'existent que pendant l'exécution du pipeline.
| Champs | Variables | |
|---|---|---|
| Objectif | accéder à des champs ou les stocker dans des documents ; | générer ou accéder à des valeurs temporaires lors de l'exécution du pipeline ; |
| Utilisation du SDK | field("name") |
variable("name") |
| Champ d'application | local au document actuel | du niveau mondial à celui des pipelines et sous-pipelines. |
| Références non définies | est égal à absent |
génère une erreur d'exécution |
Champ d'application :
Alors que les champs sont limités au document local, les variables sont définies dans un champ distinct et restent accessibles dans toutes les étapes jusqu'à la première occurrence d'une étape qui "fusionne" plusieurs documents (comme aggregate(...) ou distinct(...)). Les étapes qui "fusionnent" plusieurs documents ne permettent pas d'utiliser des références de variables par la suite, car en fusionnant les résultats de l'étape précédente, il n'y a plus qu'une seule valeur pour la variable.
À faire : référencez une variable après avoir filtré les champs du document.
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();
Ne faites pas référence à une variable après une agrégation.
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();
Références non définies :
Il est possible de faire référence à un champ non défini (qui est simplement évalué à absent), mais toute tentative de référence à une variable non définie échouera lors de la validation de la requête. En ce sens, les références de champ peuvent être considérées comme effectuant une recherche dans une carte au moment de l'exécution, tandis que les références de variable sont plus proches des variables dans un langage de programmation compilé de manière statique.
Portée globale et sous-requêtes
Les variables sont essentielles lorsque vous travaillez avec des pipelines imbriqués. Une sous-pipeline s'exécute dans son propre champ d'application et ne peut accéder qu'aux champs des documents qu'il traite actuellement. Pour utiliser une valeur du document "parent" dans une sous-requête, vous devez d'abord la définir comme variable à l'aide de l'étape 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();
Variables qui se chevauchent
Si vous définissez une variable avec un nom déjà défini dans une étape let(...) précédente, la variable précédente sera écrasée. Cela peut être utilisé pour mettre à jour l'état temporaire au fur et à mesure de la progression du pipeline.
Les variables référencées dans le sous-pipeline suivent les règles de portée lexicale que l'on trouve dans de nombreux langages de programmation. Elles font référence aux variables portant le même nom définies par le pipeline le plus proche (parent).
Comparaison avec add_fields(...)
L'étape let(...) se comporte de la même manière que l'étape add_fields(...), mais au lieu d'ajouter des champs au document, elle attribue des valeurs aux variables.