Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Operaciones de expresión de agregación

En esta guía, puedes aprender a usar el controlador Java de MongoDB para construir expresiones para utilizar en el pipeline de agregación. Puedes realizar operaciones de expresiones con métodos Java detectables y directamente tipos, en lugar de documentos BSON. Debido a que estos métodos siguen el patrón de la interfaz fluida, puedes encadenar operaciones de agregación para crear un código que sea más compacto y naturalmente legible.

Las operaciones de esta guía utilizan métodos del com.mongodb.client.model.mqlPaquete. Estos métodos proporcionan una forma idiomática de usar la API de consulta, el mecanismo mediante el cual el controlador interactúa con una implementación de MongoDB. Para obtener más información sobre la API de consulta, consulte la documentación del manual del servidor.

Los ejemplos de esta guía asumen que incluyes las siguientes importaciones estáticas en tu código:

import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Accumulators.*
import static com.mongodb.client.model.Projections.*;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.mql.MqlValues.*;
import static java.util.Arrays.asList;

Para acceder a los campos de documentos en una expresión, es necesario referenciar el documento actual que está siendo procesado por el pipeline de agregación. Usa el current() método para referirse a este documento. Para acceder al valor de un campo, debes usar el método apropiado según el tipo, como getString() o getDate(). Cuando especificas el tipo para un campo, aseguras que el controlador proporcione solo aquellos métodos que sean compatibles con ese tipo. El siguiente código muestra cómo hacer referencia a un campo string llamado name:

current().getString("name")

Para especificar un valor en una operación, pásalo al método constructor of() para convertirlo en un tipo válido. El código siguiente muestra cómo referenciar un valor de 1.0:

of(1.0)

Para crear una operación, encadene un método a su campo o referencia de valor. Puede crear operaciones más complejas encadenando métodos adicionales.

El siguiente ejemplo crea una operación para encontrar pacientes en Nuevo México que hayan ido al consultorio del doctor al menos una vez. La operación realiza las siguientes acciones:

  • Comprueba si el tamaño de la matriz visitDates es mayor que 0 utilizando el método gt()

  • Comprueba si el valor del campo state es “Nuevo México” utilizando el método eq()

El método and() vincula estas operaciones para que la etapa de la pipeline coincida solo con los documentos que cumplan ambos criterios.

current()
.getArray("visitDates")
.size()
.gt(of(0))
.and(current()
.getString("state")
.eq(of("New Mexico")));

Mientras que algunos etapas de agregación, como group(), aceptan operaciones directamente, otras etapas esperan que primero incluyas tu operación en un método como computed() o expr(). Estos métodos, que aceptan valores de tipo TExpression, permiten utilizar expresiones en ciertas agregaciones.

Para completar la etapa del pipeline de agregación, incluye tu expresión en un método del generador de agregados. La siguiente lista proporciona ejemplos de cómo incluir tu expresión en métodos comunes del builder de agregados:

  • match(expr(<expression>))

  • project(fields(computed("<field name>", <expression>)))

  • group(<expression>)

Para aprender más sobre estos métodos, consulta Aggregates desarrolladores.

Los ejemplos utilizan el método asList() para crear una lista de etapas de agregación. Esta lista se pasa al método aggregate() de MongoCollection.

Puede utilizar estos métodos constructores para definir valores para su uso en expresiones de agregación de Java.

Método
Descripción

Hace referencia al documento actual que está siendo procesado por la pipeline de agregación.

Hace referencia al documento actual que está siendo procesado por el canal de agregación como un valor de mapa.

Devuelve un tipo MqlValue correspondiente al primitivo proporcionado.

Devuelve una matriz de tipos MqlValue correspondiente a la matriz de primitivos proporcionada.

Devuelve un valor de entrada.

Devuelve un mapa vacío.

Devuelve el valor nulo tal como existe en la API de consulta.

Importante

Al asignar un valor a uno de estos métodos, el controlador lo interpreta literalmente. Por ejemplo, of("$x") representa el valor de la cadena "$x", en lugar de un campo llamado x.

Consulte cualquiera de las secciones en Operaciones para ver ejemplos usando estos métodos.

Las siguientes secciones proporcionan información y ejemplos acerca de las operaciones de expresiones de agregación disponibles en el controlador. Las operaciones se categorizan por propósito y funcionalidad.

Cada sección incluye una tabla que describe los métodos de agregación disponibles en el controlador y los operadores de expresión correspondientes en la API de consulta. Los nombres de los métodos enlazan con la documentación de la API, y los nombres de los operadores de canalización de agregación enlazan con descripciones y ejemplos en la documentación del manual del servidor. Si bien cada método Java es equivalente a la expresión de la API de consulta correspondiente, pueden diferir en los parámetros esperados y la implementación.

Nota

El controlador genera una expresión Query API que podría ser diferente de la expresión Query API proporcionada en cada ejemplo. Sin embargo, ambas expresiones darán el mismo resultado de agregación.

Importante

El driver no proporciona métodos para todos los operadores de la pipeline de agregación en la query API. Si debes usar una operación no compatible en una agregación, debes definir toda la expresión usando el tipo BSON Document. Para obtener más información sobre el tipo Document, consulta Documentos.

Puedes realizar una operación aritmética en un valor de tipo MqlInteger o MqlNumber utilizando los métodos descritos en esta sección.

Supongamos que tienes datos meteorológicos de un año específico que incluyen la medición de precipitaciones (en pulgadas) para cada día. Quieres encontrar la precipitación media, en milímetros, para cada mes.

El operador multiply() multiplica el campo precipitation por 25.4 para convertir el valor a milímetros. El método de acumulador avg() devuelve el promedio como el campo avgPrecipMM. El método group() agrupa los valores por el mes proporcionado en el campo date de cada documento.

El siguiente código muestra el pipeline para esta agregación:

var month = current().getDate("date").month(of("UTC"));
var precip = current().getInteger("precipitation");
asList(group(
month,
avg("avgPrecipMM", precip.multiply(25.4))
));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $group: {
_id: { $month: "$date" },
avgPrecipMM: {
$avg: { $multiply: ["$precipitation", 25.4] } }
} } ]

Puedes realizar una operación de arreglo en un valor de tipo MqlArray utilizando los métodos descritos en esta sección.

Supón que cuentas con una colección de películas, cada una de las cuales contiene un arreglo de documentos anidados con los próximos horarios de funciones. Cada documento anidado contiene un arreglo que representa el número total de asientos en el teatro, donde la primera entrada del arreglo es el número de asientos premium y la segunda entrada es el número de asientos regulares. Cada documento anidado también contiene el número de tickets que ya se han comprado para la función. Un documento en esta colección podría parecerse al siguiente:

{
"_id": ...,
"movie": "Hamlet",
"showtimes": [
{
"date": "May 14, 2023, 12:00 PM",
"seats": [ 20, 80 ],
"ticketsBought": 100
},
{
"date": "May 20, 2023, 08:00 PM",
"seats": [ 10, 40 ],
"ticketsBought": 34
}]
}

El método filter() solo muestra los resultados que coinciden con el predicado proporcionado. En este caso, el predicado utiliza sum() para calcular el número total de plazas y compara ese valor con el número de ticketsBought con lt(). El método project() almacena estos resultados filtrados como un nuevo arreglo availableShowtimes.

Tip

Debes especificar el tipo del arreglo que recuperas con el método getArray() si trabajas con los valores del arreglo como su tipo específico.

En este ejemplo, especificamos que la matriz seats contiene valores de tipo MqlDocument para que podamos extraer campos anidados de cada entrada de la matriz.

El siguiente código muestra el pipeline para esta agregación:

var showtimes = current().<MqlDocument>getArray("showtimes");
asList(project(fields(
computed("availableShowtimes", showtimes
.filter(showtime -> {
var seats = showtime.<MqlInteger>getArray("seats");
var totalSeats = seats.sum(n -> n);
var ticketsBought = showtime.getInteger("ticketsBought");
var isAvailable = ticketsBought.lt(totalSeats);
return isAvailable;
}))
)));

Nota

Para mejorar la legibilidad, el ejemplo anterior asigna valores intermedios a las variables totalSeats y isAvailable. Si no extrae estos valores intermedios en variables, el código aún produce resultados equivalentes.

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
availableShowtimes: {
$filter: {
input: "$showtimes",
as: "showtime",
cond: { $lt: [ "$$showtime.ticketsBought", { $sum: "$$showtime.seats" } ] }
} }
} } ]

Puede realizar una operación booleana en un valor de tipo MqlBoolean utilizando los métodos descritos en esta sección.

Método Java
Operador de canalización de agregación

Supón que quieres clasificar las mediciones de temperatura atmosférica muy bajas o altas (en grados Fahrenheit) como extremas.

El operador or() verifica si las temperaturas son extremas comparando el campo temperature con valores predefinidos usando lt() y gt(). El método project() registra este resultado en el campo extremeTemp.

El siguiente código muestra el pipeline para esta agregación:

var temperature = current().getInteger("temperature");
asList(project(fields(
computed("extremeTemp", temperature
.lt(of(10))
.or(temperature.gt(of(95))))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
extremeTemp: { $or: [ { $lt: ["$temperature", 10] },
{ $gt: ["$temperature", 95] } ] }
} } ]

Puede realizar una operación de comparación en un valor de tipo MqlValue utilizando los métodos descritos en esta sección.

Tip

El método cond() es similar al operador ternario en Java y deberías usarlo para ramas sencillas basadas en un valor booleano. Deberías utilizar los métodos switchOn() para comparaciones más complejas, como realizar coincidencias de patrones en el tipo de valor u otros controles arbitrarios sobre el valor.

El siguiente ejemplo muestra un pipeline que coincide con todos los documentos donde el campo location tiene el valor "California":

var location = current().getString("location");
asList(match(expr(location.eq(of("California")))));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $match: { location: { $eq: "California" } } } ]

Puede realizar una operación condicional utilizando los métodos descritos en esta sección.

Supongamos que tiene una colección de clientes con su información de membresía. Originalmente, los clientes eran miembros o no. Con el tiempo, se introdujeron los niveles de membresía y se utilizó el mismo campo. La información almacenada en este campo puede ser de varios tipos diferentes, y desea crear un valor estandarizado que indique su nivel de membresía.

El método switchOn() verifica cada cláusula por orden. Si el valor coincide con el tipo indicado por la cláusula, esa cláusula determina el valor de string correspondiente al nivel de membresía. Si el valor original es una string, representa el nivel de membresía y se utiliza ese valor. Si el tipo de dato es booleano, retorna Gold o Guest para el nivel de membresía. Si el tipo de dato es un arreglo, retorna el string más reciente del arreglo que coincide con el nivel de membresía más reciente. Si el campo member es de un tipo desconocido, el método switchOn() proporciona un valor por defecto de Guest.

El siguiente código muestra el pipeline para esta agregación:

var member = current().getField("member");
asList(project(fields(
computed("membershipLevel",
member.switchOn(field -> field
.isString(s -> s)
.isBoolean(b -> b.cond(of("Gold"), of("Guest")))
.<MqlString>isArray(a -> a.last())
.defaults(d -> of("Guest"))))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
membershipLevel: {
$switch: {
branches: [
{ case: { $eq: [ { $type: "$member" }, "string" ] }, then: "$member" },
{ case: { $eq: [ { $type: "$member" }, "bool" ] }, then: { $cond: {
if: "$member",
then: "Gold",
else: "Guest" } } },
{ case: { $eq: [ { $type: "$member" }, "array" ] }, then: { $last: "$member" } }
],
default: "Guest" } }
} } ]

Puedes aplicar funciones personalizadas a valores de tipo MqlValue utilizando los métodos descritos en esta sección.

Para mejorar la legibilidad y permitir la reutilización del código, puedes mover el código redundante a métodos estáticos. Sin embargo, no es posible encadenar métodos estáticos directamente en Java. El método passTo() te permite encadenar valores en métodos estáticos personalizados.

Método Java
Operador de canalización de agregación

No hay operador correspondiente

Supongamos que quieres determinar cómo se está desempeñando una clase en comparación con algunos puntos de referencia. Quiere encontrar la calificación final promedio para cada clase y compararla con los valores de referencia.

El siguiente método personalizado gradeAverage() toma una matriz de documentos y el nombre de un campo entero compartido entre ellos. Calcula el promedio de ese campo en todos los documentos de la matriz proporcionada y determina el promedio de ese campo en todos los elementos de la matriz proporcionada. El método evaluate() compara un valor proporcionado con dos límites de rango proporcionados y genera una cadena de respuesta basada en la comparación de los valores:

public static MqlNumber gradeAverage(MqlArray<MqlDocument> students, String fieldName) {
var sum = students.sum(student -> student.getInteger(fieldName));
var avg = sum.divide(students.size());
return avg;
}
public static MqlString evaluate(MqlNumber grade, MqlNumber cutoff1, MqlNumber cutoff2) {
var message = grade.switchOn(on -> on
.lte(cutoff1, g -> of("Needs improvement"))
.lte(cutoff2, g -> of("Meets expectations"))
.defaults(g -> of("Exceeds expectations")));
return message;
}

Tip

Una de las ventajas de utilizar el método passTo() es que se pueden reutilizar los métodos personalizados para otras agregaciones. Puedes utilizar el método gradeAverage() para calcular el promedio de calificaciones para grupos de estudiantes filtrados, por ejemplo, por año de ingreso o distrito, no solo por su clase. Se puede usar el método evaluate() para evaluar, por ejemplo, el desempeño de un estudiante individual, o el desempeño de toda una escuela o distrito.

El método passArrayTo() toma todos los estudiantes y calcula la puntuación promedio utilizando el método gradeAverage(). Luego, el método passNumberTo() utiliza el método evaluate() para determinar el rendimiento de las clases. Este ejemplo almacena el resultado como el campo evaluation utilizando el método project().

El siguiente código muestra el pipeline para esta agregación:

var students = current().<MqlDocument>getArray("students");
asList(project(fields(
computed("evaluation", students
.passArrayTo(students -> gradeAverage(students, "finalGrade"))
.passNumberTo(grade -> evaluate(grade, of(70), of(85))))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
evaluation: { $switch: {
branches: [
{ case: { $lte: [ { $avg: "$students.finalGrade" }, 70 ] },
then: "Needs improvement"
},
{ case: { $lte: [ { $avg: "$students.finalGrade" }, 85 ] },
then: "Meets expectations"
}
],
default: "Exceeds expectations" } }
} } ]

Puede realizar una operación de conversión para convertir entre ciertos tipos MqlValue utilizando los métodos descritos en esta sección.

Método Java
Operador de canalización de agregación

No hay operador correspondiente

No hay operador correspondiente

Supongamos que deseas tener una colección de datos estudiantiles que incluya sus años de graduación, los cuales se almacenan como cadenas de texto. Se desea calcular el año de su reunión de cinco años y almacenar este valor en un campo nuevo.

El método parseInteger() convierte el graduationYear en un número entero para que add() pueda calcular el año de la reunión. El método addFields() almacena este resultado como un nuevo campo reunionYear.

El siguiente código muestra el pipeline para esta agregación:

var graduationYear = current().getString("graduationYear");
asList(addFields(
new Field("reunionYear",
graduationYear
.parseInteger()
.add(5))
));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $addFields: {
reunionYear: {
$add: [ { $toInt: "$graduationYear" }, 5 ] }
} } ]

Puedes realizar una operación de fecha en un valor de tipo MqlDate utilizando los métodos descritos en esta sección.

Supón que tienes datos sobre entregas de paquetes y quieres hacer coincidir las entregas que ocurrieron cualquier lunes en la zona horaria "America/New_York".

Si el campo deliveryDate contiene valores de cadena que representan fechas válidas, como "2018-01-15T16:00:00Z" o Jan 15, 2018, 12:00 PM EST, puede utilizar el método parseDate() para convertir las cadenas en tipos de fecha.

El método dayOfWeek() determina qué día de la semana es y lo convierte en un número basado en qué día es lunes según el parámetro "America/New_York". El método eq() compara este valor con 2, que corresponde al lunes según el parámetro de zona horaria proporcionado.

El siguiente código muestra el pipeline para esta agregación:

var deliveryDate = current().getString("deliveryDate");
asList(match(expr(deliveryDate
.parseDate()
.dayOfWeek(of("America/New_York"))
.eq(of(2))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $match: {
$expr: {
$eq: [ {
$dayOfWeek: {
date: { $dateFromString: { dateString: "$deliveryDate" } },
timezone: "America/New_York" }},
2
] }
} } ]

Puede realizar una operación de documento en un valor de tipo MqlDocument utilizando los métodos descritos en esta sección.

Supongamos que tiene una colección de datos de clientes antiguos que incluye direcciones como documentos secundarios en el campo mailing.address. Quiere encontrar todos los clientes que actualmente residen en el estado de Washington. Un documento de esta colección podría parecerse al siguiente:

{
"_id": ...,
"customer.name": "Mary Kenneth Keller",
"mailing.address":
{
"street": "601 Mongo Drive",
"city": "Vasqueztown",
"state": "CO",
"zip": 27017
}
}

El método getDocument() recupera el campo mailing.address como documento, por lo que el campo state anidado se puede recuperar con el método getString(). El método eq() comprueba si el valor del campo state es "WA".

El siguiente código muestra el pipeline para esta agregación:

var address = current().getDocument("mailing.address");
asList(match(expr(address
.getString("state")
.eq(of("WA"))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[
{ $match: {
$expr: {
$eq: [{
$getField: {
input: { $getField: { input: "$$CURRENT", field: "mailing.address"}},
field: "state" }},
"WA" ]
}}}]

Puede realizar una operación de mapa en un valor de tipo MqlMap o MqlEntry utilizando los métodos descritos en esta sección.

Tip

Debes representar los datos como un mapa si los datos asignan claves arbitrarias, como fechas o ID de elementos, a valores.

Método Java
Operador de canalización de agregación

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

Supón que tienes una colección de datos de inventario en la que cada documento representa un artículo individual del que eres responsable de suministrar. Cada documento contiene un campo que es un mapa de todos tus almacenes y la cantidad de copias que actualmente tienen en su inventario del artículo. Se quiere determinar el número total de copias de ítems que se tiene en todos los almacenes. Un documento en esta colección podría parecerse al siguiente:

{
"_id": ...,
"item": "notebook"
"warehouses": [
{ "Atlanta", 50 },
{ "Chicago", 0 },
{ "Portland", 120 },
{ "Dallas", 6 }
]
}

El método entries() devuelve las entradas del mapa en el campo warehouses como un arreglo. El método sum() calcula el valor total de los ítems en función de los valores del arreglo recuperados con el método getValue(). Este ejemplo almacena el resultado como el nuevo campo totalInventory usando el método project().

El siguiente código muestra el pipeline para esta agregación:

var warehouses = current().getMap("warehouses");
asList(project(fields(
computed("totalInventory", warehouses
.entries()
.sum(v -> v.getValue()))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
totalInventory: {
$sum: {
$getField: { $objectToArray: "$warehouses" },
} }
} } ]

Puedes realizar una operación de string en un valor de tipo MqlString utilizando los métodos descritos en esta sección.

Supongamos que desea generar nombres de usuario en minúsculas para los empleados de una empresa a partir de los apellidos y las identificaciones de los empleados.

El método append() combina los campos firstName y lastName en un solo nombre de usuario, mientras que el método toLower() convierte todo el nombre de usuario en minúsculas. Este ejemplo almacena el resultado como un nuevo campo username usando el método project().

El siguiente código muestra el pipeline para esta agregación:

var lastName = current().getString("lastName");
var employeeID = current().getString("employeeID");
asList(project(fields(
computed("username", lastName
.append(employeeID)
.toLower())
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
username: {
$toLower: { $concat: ["$lastName", "$employeeID"] } }
} } ]

Puedes realizar una operación de comprobación de tipo en un valor de tipo MqlValue utilizando los métodos descritos en esta sección.

Estos métodos no devuelven valores booleanos. En su lugar, se proporciona un valor por defecto que coincide con el tipo especificado por el método. Si el valor comprobado coincide con el tipo de método, se devuelve el valor comprobado. De lo contrario, se devuelve el valor por defecto proporcionado. Si deseas programar una lógica de ramificación basada en el tipo de datos, consulta switchOn().

Método Java
Operador de canalización de agregación

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

No hay operador correspondiente

Suponga que tiene una colección de datos de calificaciones. Una versión temprana del esquema de revisiones permitía a los usuarios enviar revisiones negativas sin una calificación en estrellas. Quiere convertir cualquiera de estas revisiones negativas sin calificación con estrellas para que tengan el valor mínimo de una estrella.

El método isNumberOr() devuelve el valor de rating, o un valor de 1 si rating no es un número o es nulo. El método project() devuelve este valor como un nuevo campo numericalRating.

El siguiente código muestra el pipeline para esta agregación:

var rating = current().getField("rating");
asList(project(fields(
computed("numericalRating", rating
.isNumberOr(of(1)))
)));

El siguiente código proporciona un pipeline de agregación equivalente en la Query API:

[ { $project: {
numericalRating: {
$cond: { if: { $isNumber: "$rating" },
then: "$rating",
else: 1
} }
} } ]

Volver

Agregación

En esta página