D Agregacion hf16AHXv

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 29

D_Agregación

Esquema

1-Introducción y objetivos

2-Conceptos

3-Map-Reduce

4-Aggregation Framework

5-Casos prácticos

Bibliografía
Lesson 1 of 7

Esquema
Lesson 2 of 7

1-Introducción y objetivos

4.1. Introducción y objetivos


Este tema se enfoca en los conceptos básicos de agregación y las dos

funcionalidades que tiene MongoDB para llevarlo a cabo. La lectura de las Ideas claves te ayudará
a conocer lasintaxis de los comandos utilizados para realizar la agregación de datos.

Al tratarse de un tema muy práctico, la mejor forma de estudiarlo es a través de la realización de


los trabajosasignados. Además de los trabajos, es recomendable trabajar de forma proactiva con
MongoDB, lo cual te ayudará a familiarizarte con el funcionamiento del sistema.

MongoDB permite agregar los datos de una colección a través de operaciones como sumar,
contar y otros. A lo largo de este tema, se estudiarán los conceptos básicos de agregación y los
dos métodos que utiliza MongoDB para agregardatos: Map- Reduce y, a partir de la versión 2.2,
Aggregate. En especial, se estudiará el segundo por su importancia actual.

Los objetivos que se buscan alcanzar con este tema son los siguientes:

- Comprender los métodos Map-Reduce y Aggregate.

- Diferenciar los métodos y saber aplicar uno u otro en función del caso de uso.

- Poner en práctica el uso de ambos métodos a través de ejercicios guiados.


Lesson 3 of 7

2-Conceptos

4.2 Conceptos
Cualquier persona que trabaje con bases de datos tiene que realizar con frecuencia

consultas para agrupar datos y obtener resultados a partir de ellas. Por ejemplo, si se quiere
conocer la suma total deventas que cada comercial de una empresa ha conseguido en un año, es
necesario sumar cada una de las ventas quese han hecho por comercial y agruparlas por el
nombre de ese comercial.

Al final, se obtiene una tabla en la que aparecen η comerciales con la suma de sus ventas en el
período marcado en laconsulta, que en este caso sería de un año.

En las bases de datos relacionales, este tipo de consultas se realizan con el operador group by
(paraagrupar) y sum, count, etc. para realizar cualquier operación con sus datos. MongoDB
dispone de tresmétodos para gestionar la agregación: Map-Reduce, Aggregation Framework y
operadores simples de agregación específicos.

Map-Reduce es un modelo de programación utilizado por Google para el cálculo en paralelo de


grandes volúmenes dedatos. Debido a la incursión del big data, este modelo ha tomado mucha
fuerza y se ha añadido a frameworks ytecnologías como MongoDB, Hadoop y muchas otras.

Por el contrario, MongoDB incorporó a partir de su versión 2.2 Aggregation Framework, para
poder realizar lasmismas opciones de agregación que se hacen en los lenguajes SQL
relacionales.
Aunque Map-Reduce es mucho más potente, ya que se tiene todo un lenguaje de programación
para realizarcálculos y generar salidas, también es más difícil de utilizar, por lo que es más
recomendable utilizar AggregationFramework para realizar cálculos sencillos.

Otra de las causas por la que se recomienda más utilizar Aggregation Framework es porque en
temas de rendimiento está mucho más optimizado y, por lo tanto, el tiempo de la consulta suele
sermucho menor.

Además de los dos modelos de agregación, MongoDB proporciona dos operadores simples que
no pueden incluirsedentro de los métodos de agregación descritos: count y distinct. El primero
cuenta el número de resultadosobtenidos a partir de la búsqueda y el segundo muestra los
resultados que son distintos del campo que se especifiquecomo parámetro. A continuación, se
puede ver el formato de distinct:

db.collection.distinct(, {})

Donde el atributo es el campo donde se hace el distinct y el filtro, los parámetros de la búsqueda.
Un ejemplo realsería:

db.coches.distinct("modelo", {marca: "bmw"}).


Lesson 4 of 7

3-Map-Reduce

4.3. Map-Reduce
Las operaciones de map-reduce tienen dos fases:

Una etapa de map que procesa cada documento y emite uno o más objetos para cada
documento de entrada.

Una fase de reduce que combina la salida de la operación del map.

Opcionalmente, Map-Reduce puede tener una etapa de finalización para realizar

modificaciones finales al resultado. También puede especificar una condición de consulta para s
eleccionar los documentos de entrada, así como ordenar y limitar los resultados.

Map-Reduce utiliza funciones de JavaScript personalizadas para realizar el map y el reduce de las
operaciones,así como la operación de finalización opcional. El uso de JavaScript proporciona una gran
flexibilidad encomparación con las pipelines, pero Map-Reduce es menos eficiente y más complejo.

En el siguiente recuadro se muestra la sintaxis del método Map-Reduce:

db..mapReduce(, , )

El método Map-Reduce hace uso de una función map, la cual procesa un conjunto de
documentos y, mediante elcomando emit, retorna un par clave-valor, utilizando los atributos de
cada documento. Todos los valores de cada parclave-valor son agrupados de forma en que cada
clave tendrá asociado un array con los valores apropiados.
La función reduce recibe la clave y el array de valores como primer y segundo argumento
respectivamente; latarea de esta función es realizar operaciones de agregación sobre los valores
del array y retornar el valor resultante. Este valor será asociado a la clave respectiva.

Los parámetros de agregación en la función Map-Reduce se especifican como un objeto JSON,


con los siguientesatributos:

out: es el único atributo obligatorio. Indica el nombre de la collection donde se almacenará


el resultado de la operación Map-Reduce. También puede indicarse lafunción retorne el
resultado directamente, a través del objeto {inline: 1}.

query: permite definir las condiciones de búsqueda para filtrar los documentos que serán
procesados.

sort: indica la forma en la que se ordenarán los documentos antes de ser procesados, lo
cual permite optimizar el proceso.

limit: indica el número máximo de documentos a retornar.

finalize: es una función opcional a aplicar sobre los documentos retornados por la función
reduce.

scope: indica variables globales que serán accesibles desde las funciones map, reduce y
finalize.

jsMode: valor booleano para indicar si los documentos deben convertirse a formato JSON
en vez de BSON entre las funciones map y reduce. Por defecto es false.

verbose: valor booleano que indica si se debe mostrar información sobre el tiempo de
procesado de la función Map-Reduce. El valor por defecto es true. La
siguiente captura muestra un ejemplo de ejecución del comando mapReduce para calcular
la suma los precios de todoslos documentos en la collection productos.
{
_id: ObjectId("50a8240b927d5d8b5891743c"), cust_id: "abc123",
ord_date: new Date("Oct 04, 2012"), status: 'A',
price: 25,
items: [ { sku: "mmm", qty: 5, price: 2.5 },
{ sku: "nnn", qty: 5, price: 2.5 } ]
}

La función map que procesa cada documento:

En la función, this se refiere al documento que la operación Map-


Reduce está procesando.

Por cada elemento, la función asocia sku con el nuevo objeto value q
ue contiene el
campo count a 1 y el elemento qty para el perdido, y emite el par
sku-value.

var mapFunction = function() {


for (var idx = 0; idx < this.items.length; idx++) { var key = this.items[idx].
sku;
var value = { count: 1,
qty: this.items[idx].qty
};
emit(key, value);
}
};

Se define la función reduce con dos argumentos: keySKU y


countObjVals:

CountObjVals es un array cuyos elementos son los objetos asignados


a los valores
de keySKU agrupados pasados por la función map a la función
reduce.

La función reduce la matriz countObjVals a un solo objeto reducedVa


lue que
contiene los campos count y qty.

En reduceVal, el campo count contiene la suma de los campos count


de los
elementos individuales del array, y el campo qty contiene la suma de
los
campos qty de los elementos individuales del array:

var reduceFunction = function(keySKU, countObjVals) { reducedVal = {


count: 0, qty: 0 };
for (var idx = 0; idx < countObjVals.length; idx++) { reducedVal.count += c
ountObjVals[idx].count; reducedVal.qty += countObjVals[idx].qty;
}
return reducedVal;
};

Para terminar, se define una función de finalización con


dos argumentos key y reduceVal. La función modificael
objeto reduceVal para agregar un campo computado
llamado avg y devuelve el objeto modificado:

var finalizeFunction = function (key, reducedVal) { reducedVal.avg =


reducedVal.qty/reducedVal.count;return reducedVal;
};
Para terminar, se realiza la operación de Map-Reduce en la
colección utilizando todas las funciones anteriores:

db.orders.mapReduce( mapFunction, reduceFunction, { out: { merge:


"map_reduce_example" },
query:
{ ord_date: { $gt: new Date('01/01/2012') } }, finalize: finalizeFunction
});

Esta operación utiliza el campo de consulta para seleccionar


solo aquellos documentos con ord_date mayorque la fecha
01/01/2012. Seguidamente, emite los resultados a una
colección map_reduce_example. Si ya existe la colección
map_reduce_example, la operación combinará el
contenido existente con los resultados deesta operación.
Lesson 5 of 7

4-Aggregation Framework

4.4. Aggregation Framework


El framework de agregación de MongoDB está modelado en el concepto de tuberías de
procesamiento de datos, es decir, los documentos entran en una tubería (pipeline)de varias
etapas que transforman los documentos en un resultado agregado.

Las etapas más básicas proporcionan filtros que funcionan como consultas y transformaciones
de documentosque modifican la forma del documento de salida.

El resto de operaciones proporcionan herramientas para agrupar y clasificar documentos por


campo o camposespecíficos, así como herramientas para agregar el contenido de arrays,
incluyendo arrays de documentos.Además, las etapas pueden utilizar operadores para tareas
tales como calcular el promedio o concatenaciónde cadenas.

Aggregate funciona perfectamente con la capacidad de sharding que proporciona MongoDB y


que se verá másadelante. Además, se puede utilizar índices para mejorar el rendimiento durante
algunas de sus etapas.Independientemente, Aggregate tiene una fase de optimización interna, lo
que le permite mejorarsustancialmente en rendimiento a Map-Reduce.

A continuación, se ilustra el funcionamiento de Aggregate con un ejemplo básico:

db.coches.aggregate( [

$match stage ->{$match: {marca: "BMW" } },


$group stage -> {$group: {_id: "$modelo", total: { $sum: "$precio"} } }, more stage -
> { ... },

more stage -> { ... }

El funcionamiento en etapas sería el siguiente:

Figura 2. Ejemplo de agrupación con Aggregate en MongoDB.

Como se puede ver, la etapa de filtrado ($match) es análoga


a la vista en los filtros convencionales de MongoDB, por lo
que esta operación busca los documentos según los valores
especiados.
Por otro lado, la etapa de agrupación ($group), que es quizá
la más usada en el proceso de agrupación, permiteagrupar y
realizar los cálculos sobre los documentos. Nótese que es
obligatorio especificar el campo _id en el nuevodocumento,
ya que estos son los valores a agrupar.

Es posible definir agrupaciones para campos múltiples. Esta


etapa trasforma el documento de salida, por lo que enella se
deben especificar, como se ha podido ver, los nuevos
atributos de la colección y cómo se obtienen estosatributos.
MongoDB permite utilizar los siguientes operadores:

$min: devuelve el valor mínimo de los valores numéricos.

$max: devuelve el valor máximo de los valores numéricos.

$avg: devuelve el valor medio de los valores numéricos.

$sum: calcula y devuelve la suma de los valores numéricos.

$first: devuelve el valor que resulta de aplicar una expresión al


primer documento de un grupo de documentos que comparten el
mismo grupo por un campo. Solo tiene sentido cuando los
documentos están en un orden definido. Un ejemplo de uso es en
fechas.

$last: devuelve el valor que resulta de aplicar una expresión al


último documento de un grupo de documentos que comparten el
mismo grupo por un campo. Solo tiene sentido cuando los
documentos están en un orden definido.

$addToSet: devuelve un array con todos los valores únicos que


resulta de aplicar una expresión a cada documento de un grupo de
documentos que comparten el mismo grupo por clave. El orden de
los elementos en la matriz de salida no está especificado.

$push: devuelve un array con todos los valores que resultan de la


aplicación de una expresión a cada documento de un grupo de
documentos que comparten el mismo grupo por clave.

$stdDevPop: (desde la versión 3.4) calcula la desviación estándar de


la población de los valores de entrada. Se debe utilizar si los valores
abarcan toda la población de datos que desea representar y no
porque se desee generalizar sobre una población mayor. Omite
valores no numéricos.

$stdDevSamp: (desde la versión 3.4.) Calcula la desviación estándar


de la muestra de los valores de entrada. Se debe utilizar si los valores
abarcan una muestra de una población de datos a partir de la cual se
generaliza sobre la población total. Omite valores no numéricos.

El framework de agregación permite definir un mayor número de


etapas que las dos que se han descrito anteriormente. Elesquema
general, por lo tanto, es el siguiente:

db.collection.aggregate( [ { }, { }, ... ] )

A continuación, se detallan todas las etapas posibles:

$collStats: devuelve estadísticas sobre una colección o una vista.

$project: redimensiona cada documento en el flujo, por ejemplo,


agregando nuevos

campos o eliminando campos existentes. Para cada documento de


entrada, se
genera un documento.

$match: filtra el flujo de documentos para permitir que solo los


documentos coincidentes pasen sin modificaciones a la siguiente
fase de la canalización.

$redact: redimensiona cada documento en el flujo restringiendo el


contenido
de cada documento basado en la información almacenada en los pro
pios documentos.
Incorpora la funcionalidad de $project y $match. Puede utilizarse
para implementar la redacción a nivel de campo. Para cada
documento de entrada, genera uno o cero documentos.

$limit: transmite los primeros n documentos no modificados a la


canalización donde n es el límite especificado. Para cada documento
de entrada, se obtiene un documento (para los primeros n
documentos) o cero documentos (después de los primeros n
documentos).

$skip: salta los primeros n documentos donde n es el número de


salto especificado y pasa los documentos restantes sin modificar a la
tubería. Para cada documento de entrada, se emiten documentos
cero (para los primeros n documentos) o un documento (después de
los primeros ndocumentos).

$unwind: deconstruye un campo de un array de los documentos de


entrada para generar un documento para cada elemento. Cada
documento de salida reemplaza el array con un valor de elemento.
Para cada documento de entrada, se producen n documentos donde
n es el número de elementos del array y puede ser cero para una
matriz vacía.

$group: agrupa los documentos de entrada por una expresión de


identificador especificada y aplica la(s) expresión(es)
acumuladora(s), si se especifica, a cada grupo. Consume todos los
documentos de entrada y genera un documento por cada grupo
distinto. Los documentos de salida solocontienen el campo
identificador y, si se especifica, los campos acumulados.

$sample: selecciona aleatoriamente el número especificado de


documentos de su entrada.

$sort: reordena el flujo de documentos mediante una clave de


clasificación especificada. Solo cambia el orden; Los documentos
permanecen sin modificar. Para cada documento de entrada, se
genera un documento.

$geoNear: devuelve un flujo ordenado de documentos basado en la


proximidad a un punto geoespacial. Incorpora la funcionalidad de
$match, $sort y $limit para los datos geoespaciales. Los
documentos de salida incluyen un campo de distancia adicional y
pueden incluir un campo de identificador de ubicación.

$lookup: realiza una combinación externa izquierda con otra


colección en la misma base de datos para filtrar en documentos de la
colección «unida» para su procesamiento.

$out: escribe los documentos resultantes de la tubería de agregación


en una colección. Para usar la etapa $out, debe ser la última etapa en
la tubería.

$indexStats: devuelve estadísticas sobre el uso de cada índice para la


colección.

$facet: procesa múltiples tuberías de agregación dentro de una sola


etapa en el mismo conjunto de documentos de entrada. Permite la
creación de agregaciones multifacéticas capaces de caracterizar
datos a través de múltiples dimensiones, o facetas, en una sola
etapa.

$bucket: categoriza los documentos entrantes en grupos, llamados


cubos, basados en una expresión especificada y límites de cubo.

$bucketAuto: clasifica los documentos entrantes en un número


específico de grupos, llamados cubos, en función de una expresión
especificada. Los límites del cubo se determinan automáticamente
en un intento de distribuir uniformemente los documentos en el
número especificado de cubos.

$sortByCount: agrupa los documentos entrantes basados en el valor


de una expresión especificada y, a continuación, calcula el recuento
de documentos en cada grupo distinto.

$addFields: agrega nuevos campos a los documentos. Produce


documentos que contienen todos los campos existentes de los
documentos de entrada y campos añadidos recientemente.

$replaceRoot: reemplaza un documento con el documento


incrustado especificado. La operación reemplaza todos los campos
existentes en el documento de entrada, incluido el campo _id.
Especifica un documento incrustado en el documento de entrada
para promocionar el documento incrustadoal nivel superior.

$count: devuelve un recuento del número de documentos en esta


etapa de la canalización de agregación.

$graphLookup: realiza una búsqueda recursiva en una colección. A


cada documento de salida, agrega un nuevo campo de matriz que
contiene los resultadosde recorrido de la búsqueda recursiva para
ese documento.

Los operadores de expresión se construyen para construir


expresiones en algunas de las etapas de la tubería. Algunosde ellos
ya se han visto en el tema anterior. El formato es el siguiente:
{: [ , , ... ]}

A continuación, se enumera cada tipo de operador:

Booleanos: $and, $or, $not.

De conjunto: $setEquals, $setIntersection, $setUnin, $setDi erence


,
$setIsSubset, $anyElmenetTrue, $allElementsTrue.

De comparación: $cmp, $eq, $gt, $gte, $lt, $lte, $ne .

Aritméticos: $abs, $add, $ceil, $divide, $exp, $floor, $ln, $log,


$log10, $mod, $multiply, $pow, $sqrt, $subtract, $truc.

De cadena de caracteres : $concat, $indexOfBytes, $indexOfCP, $spli


t,
$strLenBytes, $strLenCP, $strcasecmp, $substr, $substrBytes,
$substrCP, $toLower, $toUpper.

Búsqueda de texto: $meta.

Array: $arrayElemAt, $concatArrays, $filter, $indexOfArray,


$isArray, $range, $reverseArray, $reduce, $size, $slice, $zip, $in.

Variable: $map, $let.

Literal: $literal.

Date: $dayOfYear, $dayOfMonth, $dayOfWeek, $year, $month,


$week,
$hour, $minute, $second, $millisecond, $dateToString,
$isoDayOfWeek, $isoWeek, $isoWeekYear.

Condicional: $cond, $ifNull, $switch.

Tipo de datos: $type.


Lesson 6 of 7

5-Casos prácticos

4.5. Casos prácticos


En este apartado pondrás en práctica lo aprendido con el método Map-Reduce y lo compararás
con las funciones de Aggregate. Se proponen tres casos prácticos donde debes:

Insertar los datos.

Crear las funciones Map-Reduce.

Escribir la función Aggregate.

Finalmente, consultar el documento de salida de las operaciones anteriores.

Los datos del primer y segundo caso no son iguales a los datos propuestos para el tercer caso.

Caso 1: usar Map-Reduce y comparar con Aggregate

Para los siguientes ejercicios, utiliza el siguiente conjunto de documentos de


la
colección norders.

db.norders.insertMany([
{ _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25,
items:

[ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status:
"A" },

{ _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-


08"), price: 70, items:

[ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], stat
us: "A" },

{ _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-


08"), price: 50, items:

[ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status
: "A" },

{ _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-


18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },

{ _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-


19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"},

{ _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-


19"), price: 35, items:

[ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status
: "A" },
{ _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25,
items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },

{ _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items:

[ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },

{ _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-


20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 },

{ sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },

{ _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku:
"oranges", qty: 10, price: 2.5 } ], status: "A" }

])

Escribe las siguientes funciones:

var mapFunction1 = function() { emit(this.cust_id, this.price);


};
var reduceFunction1 =
function(keyCustId, valuesPrices) { return Array.sum(valuesPrices);
};

Ahora aplica las funciones sobre los documentos anteriores:

db.norders.mapReduce( mapFunction1, reduceFunction1,


{ out: "map_reduce_example" }
)
Observa que el resultado de Map-Reduce se almacena en una nueva colección
llamada map_reduce_example. El paso siguiente es ejecutar una consulta sobre esta
nueva colección.

db.map_reduce_example.find().sort({_id:1}) {
"_id" : "Ant O. Knee", "value" : 95 } { "_id" :
"Busby Bee", "value" : 125 } { "_id" : "Cam
Elot", "value" : 60 } { "_id" : "Don Quis",
"value" : 155 }

Ahora realiza la misma operación anterior, pero utilizando la función aggregate.

db.norders.aggregate([ {
$group: { _id: "$cust_id", value: { $sum: "$price" } } }, { $out:
"agg_alternative_1" ])

Repite la última consulta para comprobar el resultado.

db.agg_alternative_1.find().sort({_id:1})

Puedes observar la diferencia que hay entre el uso de Map-Reduce y Aggregate.

Caso 2: utiliza Map-Reduce y compara con Aggregate, añade además la


cláusula finalize

Escribe las siguientes funciones:

var mapFunction2 = function() {


for (var idx = 0; idx < this.items.length; idx++) { var
key = this.items[idx].sku; var value = { count: 1, qty:
this.items[idx].qty }; emit(key, value);
}
};
var
reduceFunction2 = function(keySKU, countObjVals) { reducedVal = { count: 0, qty:
0 }; for (var idx = 0; idx < countObjVals.length; idx++) {
reducedVal.count += countObjVals[idx].count; reducedVal.qty +=
countObjVals[idx].qty;
}
return reducedVal;
};

var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg =


reducedVal.qty/reducedVal.count; return reducedVal;
};

Ahora aplica las funciones sobre los documentos anteriores:

db.norders.mapReduce( mapFunction2, reduceFunction2,


{
out: { merge:
"map_reduce_example2" },
query: { ord_date: { $gte: new Date("2020-03-01") } }, finalize:
finalizeFunction2 }
);

Recuerda consultar la nueva colección producto del Map-Reduce creado


previamente.

db.map_reduce_example2.find().sort( { _id: 1 } )

Ahora realiza la misma operación anterior, pero utilizando la función


aggregate.
db.norders.aggregate( [
{ $match: { ord_date: { $gte: new Date("2020-03-
01") } } }, { $unwind: "$items" },

{ $group: { _id: "$items.sku", qty: { $sum: "$items.qty" }, orders_ids: {


$addToSet: "$_id" } } }, { $project: { value: { count: { $size: "$orders_ids"
}, qty: "$qty", avg: { $divide: [ "$qty", {
$size: "$orders_ids" } ] } } } },
{ $merge: { into: "agg_alternative_3", on: "_id", whenMatched: "replace",
whenNotMatched: "insert" } }
])

Repite la última consulta para comprobar el resultado.

db.agg_alternative_3.find().sort( { _id: 1 } )

Caso 3: utiliza Map-Reduce y compara con Aggregate, añade además la


cláusula finalize y observa la agrupación incremental.

Para el siguiente ejercicio, utiliza el siguiente conjunto de


documentos de la colección usersessions.

db.usersessions.insertMany([ {
userid: "a", start: ISODate('2020-03-03 14:17:00'), length: 95 } {
userid: "b", start: ISODate('2020-03-03 14:23:00'), length: 110}, {
userid: "c", start: ISODate('2020-03-03 15:02:00'), length: 120}, {
userid: "d", start: ISODate('2020-03-03 16:45:00'), length: 45 }, {
userid: "a", start: ISODate('2020-03-04 11:05:00'), length: 105}, {
userid: "b", start: ISODate('2020-03-04 13:14:00'), length: 120}, {
userid: "c", start: ISODate('2020-03-04 17:00:00'), length: 130}, {
userid: "d", start: ISODate('2020-03-04 15:37:00'), length: 65 } ])
db.usersessions.insertMany([
{ userid: "a", ts: ISODate('2020-03-05
14:17:00'), length: 130 }, { userid: "b", ts: ISODate('2020-03-05
14:23:00'), length: 40 }, { userid: "c", ts: ISODate('2020-03-05
15:02:00'), length: 110 }, { userid: "d", ts: ISODate('2020-03-05
16:45:00'), length: 100 } ])

Escribe las siguientes funciones:

var mapFunction = function() { var key = this.userid;


var value = { total_time: this.length, count: 1, avg_time:
0 }; emit( key, value ); };
var
reduceFunction = function(key, values) {
var reducedObject = { total_time: 0, count:0, avg_time:0 };
values.forEach(function(value) {
reducedObject.total_time += value.total_time; reducedObject.count +=
value.count; });
return reducedObject;

};
var finalizeFunction = function(key,
reducedValue) { if (reducedValue.count > 0)
reducedValue.avg_time = reducedValue.total_time / reducedValue.count; return
reducedValue; };

Ahora aplica las funciones sobre los documentos anteriores:

db.usersessions.mapReduce( mapFunction,
reduceFunction,
{
out:
"session_stats", finalize: finalizeFunction
}
)

db.session_stats.find().sort( { _id: 1 } )

Observa el resultado obtenido.

{"_id":"a","value":{"total_time":330, "count":3, "avg_time" : 110 } }{"_id":"b","value":


{"total_time":270, "count":3, "avg_time" : 90 } }{"_id":"c","value":{"total_time":360,
"count":3, "avg_time" : 120 } }{"_id":"d","value":{"total_time":210, "count":3, "avg_time"
: 70 } }

Prueba ahora la siguiente forma y observa el resultado.

db.usersessions.mapReduce( mapFunction, reduceFunction,


{
query: { ts: { $gte:
ISODate('2020-03-05 00:00:00') } },
out: { reduce: "session_stats" }, finalize: finalizeFunction
}
)

db.session_stats.find().sort( { _id: 1 } )

Realiza la misma tarea, pero ahora con aggregate. Utiliza el


siguiente conjunto de documentos de la colección usersessions.

db.usersessions.drop(); db.usersessions.insertMany([ {
userid: "a", start:ISODate('2020-03-03 14:17:00'), length: 95 }, {
userid: "b", start:ISODate('2020-03-03 14:23:00'), length: 110 }, {
userid: "c", start:ISODate('2020-03-03 15:02:00'), length: 120 }, {
userid: "d", start:ISODate('2020-03-03 16:45:00'), length: 45 }, {
userid: "a", start:ISODate('2020-03-04 11:05:00'), length: 105 }, {
userid: "b", start:ISODate('2020-03-04 13:14:00'), length: 120 },
{ userid: "c", start:ISODate('2020-03-04 17:00:00'), length: 130 },
{ userid: "d", start:ISODate('2020-03-04 15:37:00'), length: 65 } ])
db.usersessions.aggregate([
{ $group: {_id: "$userid", total_time:
{$sum: "$length" }, count: {$sum: 1 }, avg_time: {$avg: "$length" }}},
{ $project: { value: { total_time: "$total_time",
count: "$count", avg_time: "$avg_time" } } },
{ $merge: {
into: "session_stats_agg", whenMatched: [ { $set: {
"value.total_time": {$add: ["$value.total_time", "$$new.value.total_time" ] }, "value.count":
{$add: ["$value.count", "$$new.value.count" ]}, "value.avg": {$divide:
[{$add: ["$value.total_time", "$$new.value.total_time"]}, {$add: ["$value.count",
"$$new.value.count" ] } ] } } } ],
whenNotMatched: "insert"
}}
])

Ejecutar una consulta sobre la nueva colección.

db.session_stats_agg.find().sort( { _id: 1 } )

Sugerencia: una vez finalizado el tema, publica un mensaje en el Foro de


este tema dando tu punto de vista sobre las ventajas de usar Map-
Reduce y Aggregate.

Investiga un poco más sobre el tema y comenta si el hecho de que


MongoDB use JavaScript dificulta de alguna manera el uso de Map-
Reduce o Aggregate.
Después de leer todo el tema, el reto siguiente es que hagas un repaso
sobre el uso de Map-Reduce y lo compares conAggregate. En los vídeos
siguientes el profesor repasará los casos prácticos y comentará algunos
aspectos que sedeben tener en cuenta a la hora de trabajar con estos
mecanismos.
Lesson 7 of 7

Bibliografía

Bibliografía
Bradshaw, S., Brazil, E., y Chodorow, K. (2019). MongoDB: the definitive guide:

powerful and scalable data storage. O'Reilly Media.

Castillo, J. N., Garcés, J. R., Navas, M. P., Segovia, D. F. J., y Naranjo, J. E. A. (2017). Base de Datos
NoSQL:MongoDB vs. Cassandra en operaciones CRUD (Create, Read, Update, Delete). Revista
Publicando, 4(11 (1)), pp. 79-107.

Giamas, A. (2017). Mastering MongoDB 3.x: an expert's guide to building fault- tolerant
MongoDB applications.Packt Publishing.

Tiwari, S. (2011). Professional NoSQL (pp. 97-135, 217-232). John Wiley & Sons.

También podría gustarte