Docs Menu
Docs Home
/ /
Operadores de tuberías de agregación

$accumulator (operador de acumulador)

$accumulator

Define una costumbre Operador acumulador. Los acumuladores son operadores que mantienen su estado (p. ej., totales, máximos, mínimos y datos relacionados) a medida que los documentos avanzan en la canalización. Utilice el operador para ejecutar sus propias funciones de JavaScript e implementar comportamientos no compatibles con el lenguaje de consulta de MongoDB.$accumulator Véase $function también.

$accumulator está disponible en estas etapas:

  • $bucket

  • $bucketAuto

  • $group

Importante

Ejecutar JavaScript dentro de un operador de agregación puede reducir el rendimiento. Utilice el $accumulator operador solo si los operadores de canalización proporcionados no satisfacen las necesidades de su aplicación.

El operador tiene esta $accumulator sintaxis:

{
$accumulator: {
init: <code>,
initArgs: <array expression>, // Optional
accumulate: <code>,
accumulateArgs: <array expression>,
merge: <code>,
finalize: <code>, // Optional
lang: <string>
}
}
Campo
Tipo
Descripción

Cadena o código

Función utilizada para inicializar el estado. La función init recibe sus argumentos del arreglo de expresiones initArgs. Puedes especificar la definición de función como el tipo BSON Code o String.

La función init tiene la siguiente forma:

function (<initArg1>, <initArg2>, ...) {
...
return <initialState>
}

Arreglo

Opcional. Argumentos pasados ​​a la función init.

initArgs tiene la siguiente forma:

[ <initArg1>, <initArg2>, ... ]

IMPORTANTE: Al usar $bucketAuto eninitArgs la etapa, no se puede hacer referencia a la clave de grupo (es decir, no se puede usar la $<fieldName> sintaxis). En cambio, en la etapa, solo se pueden especificar valores $bucketAuto constantes initArgs en.

Cadena o código

Función utilizada para acumular documentos. La accumulate función recibe sus argumentos del estado actual y de la expresión de matriz "acumularArgs". El resultado de la accumulate función se convierte en el nuevo estado. Puede especificar la definición de la función como código o cadena de tipo BSON.

La función accumulate tiene la siguiente forma:

function(state, <accumArg1>, <accumArg2>, ...) {
...
return <newState>
}

Arreglo

Argumentos pasados a la función accumulate. Puedes utilizar accumulateArgs para especificar qué valor(es) de campo pasar a la función accumulate.

accumulateArgs tiene la siguiente forma:

[ <accumArg1>, <accumArg2>, ... ]

Cadena o código

Función utilizada para fusionar dos estados internos. merge debe ser de tipo String o Code BSON. merge devuelve el resultado combinado de los dos estados fusionados. Para obtener información sobre cuándo se llama a la función de fusión, consulte Fusionar dos estados $merge con.

La función merge tiene la siguiente forma:

function (<state1>, <state2>) {
<logic to merge state1 and state2>
return <newState>
}

Cadena o código

Opcional. Función utilizada para actualizar el resultado de la acumulación.

La función finalize tiene la siguiente forma:

function (state) {
...
return <finalState>
}

String

El lenguaje utilizado en el $accumulator código.

IMPORTANTE: Actualmente, el único valor admitido para lang jses.

Los siguientes pasos describen cómo el $accumulator operador procesa los documentos:

  1. El operador comienza en un estado inicial, definido por la función init.

  2. Para cada documento, el operador actualiza el estado según la función de acumulación. El primer argumento de la función de acumulación es el estado actual, y los argumentos adicionales se especifican en la matriz "acumulArgs".

  3. Cuando el operador necesita fusionar varios estados intermedios, ejecuta la función de fusión. Para más información sobre cuándo se llama a la función de fusión, consulte Fusionar dos estados con.$merge

  4. Si se ha definido una función de finalización, una vez que se hayan procesado todos los documentos y se haya actualizado el estado en consecuencia, la función de finalización convierte el estado en una salida final.

Como parte de sus operaciones internas, el operador $accumulator puede necesitar fusionar dos estados intermedios separados. La función merge especifica cómo el operador debe fusionar dos estados.

La función de fusión siempre fusiona dos estados a la vez. Si es necesario fusionar más de dos, la fusión resultante se fusiona con un solo estado. Este proceso se repite hasta que se fusionen todos los estados.

Por ejemplo, puede necesitar combinar dos estados en los siguientes$accumulator escenarios:

El orden con el que MongoDB procesa documentos para las funciones init(), accumulate() y merge() puede variar y podría diferir del orden en que esos documentos se especifican para la función $accumulator.

Por ejemplo, considere una serie de documentos donde los campos _id son las letras del alfabeto:

{ _id: 'a' },
{ _id: 'b' },
{ _id: 'c' }
...
{ _id: 'z' }

A continuación, considere una secuencia de agregación que ordena los documentos por el campo _id y luego utiliza una función $accumulator para concatenar los valores del campo _id:

[
{
$sort: { _id: 1 }
},
{
$group: {
_id: null,
alphabet: {
$accumulator: {
init: function() {
return ""
},
accumulate: function(state, letter) {
return(state + letter)
},
accumulateArgs: [ "$_id" ],
merge: function(state1, state2) {
return(state1 + state2)
},
lang: "js"
}
}
}
}
]

MongoDB no garantiza que los documentos se procesen en el orden ordenado, lo que significa que el campo alphabet no necesariamente se establece en abc...z.

Debido a este comportamiento, asegúrese de que su función $accumulator no necesite procesar y devolver documentos en un orden específico.

Para utilizar, debe tener habilitadas las secuencias de comandos del lado del $accumulator servidor.

Si no utiliza $accumulator (o, o), deshabilite las secuencias de comandos del lado del $function $where mapReduceservidor:

Consulta también ➤ Ejecutar MongoDB con opciones de configuración seguras.

MongoDB 6.0 actualiza el motor JavaScript interno utilizado para JavaScript del lado del servidor, expresiones, $accumulator $functiony, y de $where MozJS-60 a91 MozJS-. Varias funciones de matriz y cadena obsoletas y no estándar que existían en MozJS-60 se eliminan en MozJS-.91

Para obtener la lista completa de funciones de cadena y matriz eliminadas, consulte las 6.0 notas de compatibilidad.

Nota

Este ejemplo explica el uso del operador$accumulatorpara implementar el operador$avg, ya compatible con MongoDB. El objetivo de este ejemplo no es implementar nuevas funciones, sino ilustrar el comportamiento y la sintaxis del operador$accumulatorcon una lógica familiar.

En mongosh, cree una colección de muestra llamada books con los siguientes documentos:

db.books.insertMany([
{ _id: 8751, title: "The Banquet", author: "Dante", copies: 2 },
{ _id: 8752, title: "Divine Comedy", author: "Dante", copies: 1 },
{ _id: 8645, title: "Eclogues", author: "Dante", copies: 2 },
{ _id: 7000, title: "The Odyssey", author: "Homer", copies: 10 },
{ _id: 7020, title: "Iliad", author: "Homer", copies: 10 }
])

La siguiente operación divide los documentos groups por author y utiliza $accumulator para calcular el número promedio de copias de los libros de cada autor:

db.books.aggregate([
{
$group :
{
_id : "$author",
avgCopies:
{
$accumulator:
{
init: function() { // Set the initial state
return { count: 0, sum: 0 }
},
accumulate: function(state, numCopies) { // Define how to update the state
return {
count: state.count + 1,
sum: state.sum + numCopies
}
},
accumulateArgs: ["$copies"], // Argument required by the accumulate function
merge: function(state1, state2) { // When the operator performs a merge,
return { // add the fields from the two states
count: state1.count + state2.count,
sum: state1.sum + state2.sum
}
},
finalize: function(state) { // After collecting the results from all documents,
return (state.sum / state.count) // calculate the average
},
lang: "js"
}
}
}
}
])

Esta operación devuelve el siguiente resultado:

{ _id: "Dante", avgCopies: 1.6666666666666667 }
{ _id: "Homer", avgCopies: 10 }

El define un estado inicial $accumulator donde count y sum se establecen 0 en. Para cada documento que procesa el, actualiza el estado $accumulator mediante:

  • Incrementando count por 1 y

  • Sumar los valores del copies campo del documento sum al. La función de acumulación puede acceder al copies campo porque se pasa en el campo "acumulArgs".

Con cada documento procesado, la función acumular devuelve el estado actualizado.

Una vez procesados ​​todos los documentos, la función de finalización divide el sum de las copias entre el count de los documentos para obtener el promedio. Esto elimina la necesidad de mantener un promedio móvil calculado, ya que la función de finalización recibe el sum y el acumulados count de todos los documentos.

Esta operación es equivalente a la siguiente canalización, que utiliza el $avg operador:

db.books.aggregate([
{
$group : {
_id : "$author",
avgCopies: { $avg: "$copies" }
}
}
])

Puedes usar la opción initArgs para variar el estado inicial de. Esto puede ser útil si quieres, por $accumulator ejemplo:

  • Utilice el valor de un campo que no está en su estado para afectar su estado, o

  • Establezca el estado inicial en un valor diferente según el grupo que se esté procesando.

En mongosh, cree una colección de muestra llamada restaurants con los siguientes documentos:

db.restaurants.insertMany( [
{ _id: 1, name: "Food Fury", city: "Bettles", cuisine: "American" },
{ _id: 2, name: "Meal Macro", city: "Bettles", cuisine: "Chinese" },
{ _id: 3, name: "Big Crisp", city: "Bettles", cuisine: "Latin" },
{ _id: 4, name: "The Wrap", city: "Onida", cuisine: "American" },
{ _id: 5, name: "Spice Attack", city: "Onida", cuisine: "Latin" },
{ _id: 6, name: "Soup City", city: "Onida", cuisine: "Chinese" },
{ _id: 7, name: "Crave", city: "Pyote", cuisine: "American" },
{ _id: 8, name: "The Gala", city: "Pyote", cuisine: "Chinese" }
] )

Supongamos que una aplicación permite a los usuarios consultar estos datos para encontrar restaurantes. Podría ser útil mostrar más resultados para la ciudad donde reside el usuario. En este ejemplo, suponemos que la ciudad del usuario se llama en una variable llamada userProfileCity.

La siguiente canalización de agregación procesa los groups documentos city mediante. La operación utiliza para mostrar un número diferente de resultados de cada ciudad, dependiendo de si la ciudad del restaurante coincide con la del perfil del $accumulator usuario:

Nota

Para ejecutar este ejemplo en,mongosh reemplace <userProfileCity> en initArgs con una cadena que contenga un valor de ciudad real,Bettles como.

1db.restaurants.aggregate([
2{
3 $group :
4 {
5 _id : { city: "$city" },
6 restaurants:
7 {
8 $accumulator:
9 {
10 init: function(city, userProfileCity) { // Set the initial state
11 return {
12 max: city === userProfileCity ? 3 : 1, // If the group matches the user's city, return 3 restaurants
13 restaurants: [] // else, return 1 restaurant
14 }
15 },
16
17 initArgs: ["$city", <userProfileCity>], // Argument to pass to the init function
18
19 accumulate: function(state, restaurantName) { // Define how to update the state
20 if (state.restaurants.length < state.max) {
21 state.restaurants.push(restaurantName);
22 }
23 return state;
24 },
25
26 accumulateArgs: ["$name"], // Argument required by the accumulate function
27
28 merge: function(state1, state2) {
29 return {
30 max: state1.max,
31 restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max)
32 }
33 },
34
35 finalize: function(state) { // Adjust the state to only return field we need
36 return state.restaurants
37 }
38
39 lang: "js"
40 }
41 }
42 }
43}
44])

Si el valor de userProfileCity es Bettles, esta operación arroja el siguiente resultado:

{ _id: { city: "Bettles" }, restaurants: { restaurants: [ "Food Fury", "Meal Macro", "Big Crisp" ] } }
{ _id: { city: "Onida" }, restaurants: { restaurants: [ "The Wrap" ] } }
{ _id: { city: "Pyote" }, restaurants: { restaurants: [ "Crave" ] } }

Si el valor de userProfileCity es Onida, esta operación arroja el siguiente resultado:

{ _id: { city: "Bettles" }, restaurants: { restaurants: [ "Food Fury" ] } }
{ _id: { city: "Onida" }, restaurants: { restaurants: [ "The Wrap", "Spice Attack", "Soup City" ] } }
{ _id: { city: "Pyote" }, restaurants: { restaurants: [ "Crave" ] } }

Si el valor de userProfileCity es Pyote, esta operación arroja el siguiente resultado:

{ _id: { city: "Bettles" }, restaurants: { restaurants: [ "Food Fury" ] } }
{ _id: { city: "Onida" }, restaurants: { restaurants: [ "The Wrap" ] } }
{ _id: { city: "Pyote" }, restaurants: { restaurants: [ "Crave", "The Gala" ] } }

Si el valor de userProfileCity es cualquier otro valor, esta operación devuelve el siguiente resultado:

{ _id: { city: "Bettles" }, restaurants: { restaurants: [ "Food Fury" ] } }
{ _id: { city: "Onida" }, restaurants: { restaurants: [ "The Wrap" ] } }
{ _id: { city: "Pyote" }, restaurants: { restaurants: [ "Crave" ] } }

La función init define un estado inicial que contiene max los restaurants campos y. El max campo establece el número máximo de restaurantes para ese grupo en particular. Si el city campo del documento coincide userProfileCity con, ese grupo contiene un máximo de 3 restaurantes. De lo contrario, si el documento _id no coincide userProfileCity con, el grupo contiene como máximo un restaurante. La función init recibe los city userProfileCity argumentos y de la matriz initArgs.

Por cada documento que procesa, inserta $accumulator el name del restaurante en la restaurants matriz, siempre que el nombre no supere la longitud de restaurants con el max valor de. Con cada documento procesado, la función de acumulación devuelve el estado actualizado.

La función de fusión define cómo fusionar dos estados. La función concatena las restaurant matrices de cada estado y la longitud de la matriz resultante se limita mediante la función slice().método para garantizar que no exceda el max valor.

Una vez procesados ​​todos los documentos, la función de finalización modifica el estado resultante para devolver únicamente los nombres de los restaurantes. Sin esta función, el max campo también se incluiría en la salida, lo cual no satisface ninguna necesidad de la aplicación.

Volver

$abs

En esta página