Descripción
Define variables temporales a las que se puede hacer referencia en etapas posteriores de la canalización.
Las variables creadas en la etapa let(...) no se incluyen en los resultados finales
a menos que se asignen de forma explícita a un campo en una etapa posterior (p.ej., con
add_fields(...) o
select(...)). Esto te permite simplificar la lógica compleja
dividiéndola en componentes más pequeños y reutilizables sin desordenar los documentos de salida. La etapa let(...) es especialmente útil para las subcanalizaciones
correlacionadas, en las que una subcanalización necesita hacer referencia a un valor del alcance del documento
superior.
Ejemplos
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();
Comportamiento
Variables en comparación con campos
Mientras que los campos representan los datos almacenados en los documentos, las variables son valores temporales que solo existen durante la ejecución de la canalización.
| Campos | Variables | |
|---|---|---|
| Objetivo | acceder a campos o almacenarlos en documentos | generar o acceder a valores temporales durante la ejecución de la canalización |
| Uso del SDK | field("name") |
variable("name") |
| Alcance | local para el documento actual | global para la canalización y las subcanalizaciones |
| Referencias no definidas | se evalúa como absent |
genera un error de tiempo de ejecución |
Alcance:
Si bien los campos se limitan al documento local, las variables se definen en un
alcance independiente y siguen siendo accesibles en todas las etapas hasta la primera aparición de
una etapa que "une" varios documentos (como
aggregate(...) o
distinct(...)). Las etapas que "unen" varios
documentos no permiten que se usen referencias de variables después, ya que, al unir
los resultados de la etapa anterior, ya no hay un valor para la
variable.
Qué hacer: Haz referencia a una variable después de filtrar los campos del documento.
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();
Qué no hacer: No hagas referencia a una variable después de una agregación.
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();
Referencias no definidas:
Si bien hacer referencia a un campo no definido está bien (y solo se evalúa como absent), intentar hacer referencia a una variable no definida fallará durante la validación de la solicitud. En este sentido, las referencias de campo se pueden ver como la realización de una búsqueda en un mapa en el tiempo de ejecución, mientras que las referencias de variables son más similares a las variables en un lenguaje de programación compilado de forma estática.
Alcance global y subconsultas
Las variables son esenciales cuando se trabaja con canalizaciones anidadas. Una subcanalización se ejecuta en su propio alcance y solo puede acceder a los campos de los documentos que está procesando actualmente. Para usar un valor del documento "superior" dentro de una subconsulta, primero debes definirlo como una variable con la etapa 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 superpuestas
Si defines una variable con un nombre que ya se definió en una etapa let(...) anterior, se sobrescribirá la variable anterior. Esto se puede usar para actualizar el estado temporal a medida que avanza la canalización.
Las variables a las que se hace referencia en la subcanalización siguen las reglas de alcance léxico que se encuentran en muchos lenguajes de programación y se refieren a las variables con el mismo nombre definidas por la canalización más cercana (superior).
Comparación con add_fields(...)
La etapa let(...) se comporta de manera similar a la etapa
add_fields(...), pero, en lugar de agregar
campos al documento, asigna valores a las variables.