Gestión avanzada de datos con MongoDB
3.6 (25 ratings)
Instead of using a simple lifetime average, Udemy calculates a course's star rating by considering a number of different factors such as the number of ratings, the age of ratings, and the likelihood of fraudulent ratings.
347 students enrolled
Wishlisted Wishlist

Please confirm that you want to add Gestión avanzada de datos con MongoDB to your Wishlist.

Add to Wishlist

Gestión avanzada de datos con MongoDB

Mejora del rendimiento con índices, diseño de estructuras de datos y operaciones de agregación
3.6 (25 ratings)
Instead of using a simple lifetime average, Udemy calculates a course's star rating by considering a number of different factors such as the number of ratings, the age of ratings, and the likelihood of fraudulent ratings.
347 students enrolled
Last updated 7/2014
Spanish
Learn Fest Sale
Current price: $10 Original price: $45 Discount: 78% off
3 days left at this price!
30-Day Money-Back Guarantee
Includes:
  • 10.5 hours on-demand video
  • Full lifetime access
  • Access on mobile and TV
  • Certificate of Completion
What Will I Learn?
  • Acelerar las operaciones de lectura con los índices
  • Realizar operaciones con datos de geolocalización
  • Diseñar eficientemente nuestra estructura de datos
  • Extraer información agregada de nuestros datos (medias, máximos,...)
View Curriculum
Requirements
  • Para realizar los ejemplos del curso hay que instalar MongoDB
  • Conocimientos básicos de Javascript y NodeJS
  • Conocimientos básicos de MongoDB
Description

El curso, que es el segundo de una serie de cursos sobre MongoDB, nos permite profundizar en las tareas de gestión de datos. Vamos a ver:

  • qué tipos índices soporta MongoDB
  • cómo se usan los índices
  • cómo se evalúa el uso de los índices
  • qué criterios seguir a la hora de definir la estructura de datos de nuestra aplicación
  • qué otras posibilidades de almacenamiento nos ofrece MongoDB (colecciones limitadas, GridFS,...)
  • cómo realizamos operaciones de agregación en MongoDB
  • cómo utilizamos MapReduce en MongoDB

MongoDB cuenta con varios tipos de índices para mejorar el rendimiento de las operaciones de lectura. Los índices geoespaciales nos permiten trabajar con datos de geolocalización, por ejemplo filtrando la información por la distancia a la que se encuentra de un punto sobre la superficie de la Tierra. Los índices de texto, definitivamente incluidos en MongoDB a partir de la versión 2.6, nos permiten realizar búsquedas sobre textos.

También veremos cómo diseñar la estructura de datos en la que almacenaremos la información de nuestra aplicación. Aunque MongoDB no es una base de datos relacional, y no impone una estructura rígida a los datos de nuestra aplicación, es conveniente tener en cuenta las implicaciones de rendimiento que las decisiones sobre esta estructura pudieran ocasionar.

MongoDB cuenta con varias alternativas para llevar a cabo operaciones de agregación de los datos (medias, máximas, sumas,...). En este curso nos ocuparemos principalmente del sistema de agregación de MongoDB, y de la implementación MapReduce realizada por MongoDB.

El curso consta de una serie de lecciones en formato vídeo, que constan tanto de contenidos teóricos cómo prácticos. La longitud de los vídeos suele ser inferior a los diez minutos, aunque en ocasiones alguno de ellos se acerca a los quince minutos.

Veremos cómo replicar en vuestros equipos los ejemplos incluidos en los vídeos, para que hagáis con vuestras propias manos las operaciones que os muestro. Cada cierto número de lecciones se incluye un grupo de preguntas para comprobar el grado de compresión de los temas tratados. En ocasiones, se incluye algún ejercicio práctico entre las preguntas, que requiere la descarga de algún archivo y el manejo de un servidor MongoDB. También se incluyen diversos ejemplos de código NodeJS, para ver cómo se trabaja con MongoDB desde una aplicación.

El curso puede ser completado en unas seis semanas, dedicando unas 8 - 12 horas a la semana. En todo caso, elige el ritmo que más se adapte a tu disponibilidad.

Who is the target audience?
  • Administradores de bases de datos
  • Programadores web
  • Emprendedores
  • Aficionados a la informática
Students Who Viewed This Course Also Viewed
Curriculum For This Course
Expand All 93 Lectures Collapse All 93 Lectures 10:34:01
+
Introducción al curso
1 Lecture 03:18
Introducción
03:18
+
Índices
37 Lectures 04:22:38
Sin índices, para filtrar una colección hay que recorrerla completamente (escanear), y comparar cada documento de la colección con las condiciones de la consulta.
En la medida de lo posible hay que evitar que nuestras consultas se resuelvan mediante escaneos de las colecciones, ya que en general son muy lentos.
Con índices, para filtrar una colección se buscan en uno de ellos los valores que cumplen las condiciones de la consulta.
Esos valores tendrán asociados unos identificadores que apuntan directamente a los documentos que cumplen las condiciones de la consulta.
Preview 03:44

En MongoDB todos los índices se guardan en estructuras jerárquicas denominadas árboles-B (B-tree).
En los árboles-B cada nivel del árbol define la distribución de los valores del índice en el siguiente nivel, y los valores del índice se almacenan de manera ordenada.
Cada valor distinto del campo o de los campos incluidos en el índice, tiene asociado uno o varios valores que apuntan a la localización dentro de la colección de los documentos que contienen ese valor o valores.
Estructura de árbol-B
05:50

El índice es menor en tamaño que la colección, y además recorrerlo es más rápido por el hecho de tener una estructura en árbol-B.
El caso más óptimo de utilización de un índice es cuando los campos que se han de devolver están incluidos en el índice. En ese caso ni siquiera se accede a la colección.
Cuando se utiliza un índice para ordenar, lo que se hace es recorrer el árbol-B del índice en el orden especificado, recuperando para cada valor del índice la localización de cada documento.
Ventajas de los índices
04:04

Introducción a los índices
5 questions

En MongoDB los índices se crean con db.colección.ensureIndex( patrón de clave ), si no existe previamente. El patrón de clave o key pattern especifica qué campo o campos se incluyen en el índice.
Un ejemplo sería { edad : 1 , pais : -1 }, que crea un índice sobre los campos edad y pais de una colección. El orden se especifica con 1 (ascendente) ó -1 (descendente).
Cada colección cuenta con un índice único automáticamente creado sobre el campo _id. El resto de índices se han de crear de manera explícita con db.colección.ensureIndex. Los índices se usan de manera automática en las consultas, no hay que hacer nada para forzar su uso.
Creación de índices
04:30

Para averiguar cuántos índices tenemos en una colección concreta haremos db.colección.getIndexes(). Podemos conocer cuál es el tamaño del índice creado con db.colección.stats().
Para ver como afectan los índices vamos a trabajar con una colección de datos de puntuaciones que ya vimos en otro tema. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.PrimerosPasosIndices.zip y descomprimirlo.
Ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuaciones2.js. Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior.
Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección puntuaciones y luego la alimenta con 500000 documentos (con puntuaciones aleatorias).
Primeros pasos con los índices
08:02

Creación de índices
4 questions

El índice que se crea por defecto puede incluir claves repetidas. Para crear un índice único lo que haremos será db.colección.ensureIndex( patrón de clave , { unique : true } ).
Si intentamos crear un índice único sobre una colección que ya tiene documentos con claves repetidas dará error.
Si tenemos una colección con un campo que sólo aparece en algunos documentos, para crear un índice sobre él sería útil indicar que es un índice disperso, para que el índice no incluya información de los documentos que no lo contienen.
Esto se indica con db.colección.ensureIndex( patrón de clave, { sparse : true } ). Hay que tener cuidado con estos índices, puesto que bajo determinadas circunstancias pueden producir resultados curiosos.
Índices únicos y esparcidos
07:11

Podemos utilizar un índice TTL (Time To Live), para que los documentos se eliminen tras un determinado tiempo, o en un momento determinado.
Si tenemos que crear un índice sobre una colección grande, y no queremos bloquear el acceso a la base de datos, podemos crearla en segundo plano ( { background : true } ). Tardará más, y el índice creado ocupará algo más.
Si queremos crear un índice único sobre un campo que ya cuenta con claves repetidas podemos especificar { dropDups : true } para eliminar los documentos que sean necesarios. Pero los documentos eliminados no son los que queramos, si no que MongoDB los elimina de forma arbitraria. A partir de la versión 2.6 de MongoDB se desaconseja su uso.
Índices TTL y otras opciones
10:26

Opciones para la creación de índices
4 questions

Los índices que debemos crear están absolutamente definidos por la forma en la que se accede a los datos. En ocasiones puede pasar que un mismo campo participe en varias condiciones de filtrado o de ordenación.
En esas circunstancias hay que decidir si crear un índice con sólo ese campo, o incluirlo en uno compuesto con otros. Para decidir esto hay que tener en cuenta cuándo un índice puede utilizarse.
Para comprobar la diferencia entre usar índices o no, vamos a trabajar con una colección de puntuaciones con un modelo de documento que ya hemos visto.
Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.ComoSeUsanIndices.zip y lo descomprimis. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuacionesMasiva.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección puntuaciones y luego la alimenta con un millón de documentos (puntuaciones aleatorias de 0 a 99.99).
La forma de averiguar si un índice se utiliza en una consulta es añadir explain() al final de ésta. Por ejemplo db.colección.find().explain(). Esto ejecuta la consulta, pero no devuelve los documentos que cumplen las condiciones de la consulta, sino información acerca de cómo se lleva a cabo.
¿Cómo se usan los índices?
11:57

Para poder usar un índice compuesto en una operación, las condiciones de filtrado deben afectar a un subconjunto cabecero de los campos del índice.
También se utilizará si el criterio de ordenación se impone sobre un subconjunto cabecero de los campos del índice, a no ser que el primero o los primeros estén incluidos en las condiciones de filtrado. En ese caso tiene que ser un subconjunto cabecero de los campos no utilizados en las condiciones de filtrado.
Para los ejemplos vamos a trabajar con una colección de puntuaciones con un modelo de documento que ya hemos visto. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.CuandoSeUsanIndices.zip y lo descomprimis.
Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuaciones.js. Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior.
¿Cuándo se usan los índices?
11:10

Cada cierto tiempo MongoDB evalúa el coste de utilizar todos los índices posibles para una consulta, y almacena los resultados. Hasta que no vuelve a realizar esta evaluación, utiliza esos resultados para decidir qué índices utilizar para cada operación.
En algunos casos puede que la consulta utilice uno de los índices que no nos interesan. Para asegurarnos de que una consulta utiliza un índice concreto podemos hacer db.colección.find( criterio , proyeccion ).hint( criterio de ordenación ).
En el archivo 2.QueIndiceSeUsa.zip tenéis el código de un ejemplo NodeJS que fuerza el uso de un determinado índice con hint.
¿Qué índice se usa?
09:16

Uso de índices
4 questions

En general los índices aceleran las lecturas de datos y ralentizan las escrituras, si bien las actualizaciones y eliminaciones de datos pueden acelerarse si utilizan índices para encontrar los documentos a actualizar o eliminar.
Si los índices que se utilizan caben en memoria, MongoDB funciona mucho mejor. De hecho este es uno de los criterios más importante a la hora de crear índices, intentar que quepan en memoria.
Si tenemos una colección con operaciones de escritura muy frecuentes, no es muy recomendable tener un montón de índices. Cuantos más documentos tenga una colección, más beneficioso será tener índices que aceleren las lecturas. Existe un compromiso entre operaciones de lectura y escritura a la hora de decidir qué índices creamos en una colección.
En las operaciones de actualización, si el nuevo documento no cabe hay que guardarlo en otro lugar del fichero, es decir se mueve el documento. Todos las claves de los índices de la colección han de actualizarse para que apunten al nuevo emplazamiento del documento. Si se pueden evitar operaciones que provocan estos movimientos de documentos mejor.
Preview 09:26

En algunos casos, el uso de un índice no mejora mucho el rendimiento de las consultas. Por ejemplo, los operadores de comparación ($gt, $lt,...) pueden beneficiarse del uso de un índice, pero si la condición se traduce en que la gran mayoría de los documentos de la colección la cumplen, no es muy eficiente.
Las condiciones que niegan también son ineficientes ($ne, $nin, $exists : false), y además puede que tengan que acceder a todos los documentos de la colección incluso con índices.
Otro tipo de operador de consultas que puede no ser eficiente, incluso con el uso de índices, es $regex. Si la condición es sobre el inicio de un campo ($regex : /^Prueba/) puede usar eficientemente un índice. En caso contrario no.
Si creamos un índice sobre un campo con poca selectividad, la mejora de rendimiento tampoco será muy importante.
Índices que no aportan mucho
05:25

Vamos a ver diversos ejemplos de operaciones que no se benefician demasiado de la existencia de índices. Para ello utilizaremos la colección de puntuaciones de nuevo.
Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.IndicesNoAportanMucho.Ejemplos.zip y descomprimirlo. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuaciones.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección puntuaciones y luego la alimenta con 1000000 documentos (puntuaciones aleatorias de 0 a 99.99).
Índices que no aportan mucho. Ejemplos
08:13

Consideraciones sobre los índices
5 questions

Los índices 2d realizan sus cálculos suponiendo que la Tierra es un plano. Una posición sobre la Tierra se guarda con un par de valores ( [ x , y ] ), donde x es la longitud, e y la latitud.
Pueden formar parte de un índice compuesto, siempre que el campo de localización sea el primero y que el número total de campos del índice sea 2.
Índices geoespaciales 2d
03:23

Los índices 2dsphere realizan sus cálculos suponiendo que la Tierra es una esfera. Una posición sobre la Tierra se guarda con un objeto GeoJSON del tipo Point ( { type : "Point" , coordinates: [ <longitud>, <latitud> ] } ).
Por defecto GeoJSON supone que el datum es WGS84. Además puede trabajar con otros tipos de objetos GeoJSON.
Los índices 2dsphere también pueden trabajar con posiciones del tipo 2d, convirtiendo cada par de valores x,y en un objeto GeoJSON del tipo Point. Pueden formar parte de un índice compuesto, en el que los campos pueden ocupar cualquier orden y el límite de campos es el general (31).
Índices geoespaciales 2dsphere
06:42

Las operaciones que se pueden realizar con campos indexados geoespacialmente son la inclusión ($geoWithin), la intersección ($geoIntersects) y la proximidad ($near).
Esta última es la única que requiere de un índice geoespacial para que funcione. La inclusión puede realizarse sin que se haya creado un índice geoespacial, si bien su creación mejorará su rendimiento.
La intersección no funciona con índice 2d, ya que trabaja con datos de una esfera.
Índices geoespaciales. Operaciones
06:53

Índices geoespaciales
5 questions

Para poder filtrar los datos de una colección (expresados como objetos GeoJSON) por la cercanía a una localización necesitaremos crear un índice 2dsphere. Para ello podemos hacer db.colección.ensureIndex( { localizacion : "2dsphere" } ).
Observad que los resultados de la operación de cercanía ($near) se ordenan por distancia ascendente, y que la máxima distancia se expresa en metros.
Para todas las operaciones con datos de tipo GeoJSON vamos a trabajar con una colección de tiendas. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.Indices2dsphereCercania.zip y descomprimirlo. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaTiendas3d.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección tiendas3d y luego la alimenta con 2000 documentos (localizaciones aleatorias entre -10 , 37 y 3, 43, y entre -55, -75 y 11, -35).
Preview 07:12

Índices 2dsphere . Cercanía
2 questions

Podemos crear índices compuestos en los que un campo sea de tipo 2dsphere. Vamos a ver ejemplos con nuestra colección de tiendas con datos de geolocalización de tipo GeoJSON Point.
Para consultar las tiendas de un determinado tipo que estén cerca de un punto, crearemos db.tiendas3d.ensureIndex( { localizacion : "2dsphere" , tipo : 1 } ) y db.tiendas3d.ensureIndex( { tipo : 1 , localizacion : "2dsphere" } ) para hacer pruebas
Índices 2dsphere. Índice compuesto
09:06

Índices 2dsphere. Índice compuesto
2 questions

Las operaciones de inclusión ($geoWithin) que podemos hacer con objetos GeoJSON son dos: inclusión en un polígono ($polygon), y en un círculo sobre la superficie de la Tierra ($centerSphere). En este último caso el parámetro de distancia se expresa en radianes.
En este caso la creación de un índice 2dsphere no es obligatoria, aunque su existencia debería mejorar el rendimiento de las operaciones de inclusión.
Índices 2dsphere. Inclusión
06:01

Índices 2dsphere. Inclusión
2 questions

Las operaciones de intersección ($geoIntersects) que podemos hacer con objetos GeoJSON son tres: intersección con un punto, una línea o un polígono. Para cada una de ellas tendremos que usar un objeto GeoJSON distinto (Point, LineString, Polygon) en el campo $geometry.
En este caso la creación de un índice 2dsphere no es obligatoria, aunque su existencia debería mejorar el rendimiento de las operaciones de intersección.
Índices 2dsphere. Intersección
06:34

Índices 2dsphere. Intersección
3 questions

Para poder filtrar los datos de una colección (expresados como un array de pares de coordenadas x, y) por la cercanía a la localización necesitaremos crear un índice 2d.
Para ello podemos hacer db.tiendas2d.ensureIndex( { localizacion : "2d" } ). Al igual que en el caso 2dsphere los resultados se ordenan por distancia ascendente.
Los resultados sobre un índice 2d siempre se limitan por defecto a 100. Podemos cambiarlo con cursor.limit(). La máxima distancia en este caso se expresa en las mismas unidades utilizadas en los valores de x e y.
Para todas las operaciones con datos de tipo par de coordenadas x e y vamos a trabajar con una colección de tiendas. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.Indices2dCercania.zip y descomprimirlo. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaTiendas2d.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección tiendas2d y luego la alimenta con 2000 documentos (localizaciones aleatorias entre -10 , 37 y 3, 43, y entre -55, -75 y 11, -35).
Índices 2d. Cercanía
06:17

Índices 2d. Cercanía
2 questions

En el caso de contar con datos de localización en el formato de array de pares de coordenadas x,y, también podemos crear un índice 2dsphere.
De esta manera podemos utilizar la sintaxis de las búsquedas por cercanía de 2dsphere, en la que la máxima distancia se expresa en metros, los resultados no se limitan a 100 por defecto, y se utiliza geometría esférica para realizar los cálculos.
Índices 2d. Cercanía con 2dsphere
04:36

Índices 2d. Cercanía con 2dsphere
2 questions

En el caso 2d, sólo tenemos una posibilidad para crear un índice compuesto. Primero el campo de los datos de localización, y después un único campo no especial.
Por ejemplo, db.tiendas2d.ensureIndex( { localizacion : "2d" , tipo : 1 } )
Índices 2d. Índice compuesto
03:28

Índices 2d. Índice compuesto
2 questions

Las operaciones de inclusión ($geoWithin) que podemos hacer con pares de coordenadas x,y son tres: inclusión en un polígono ($polygon), en un rectángulo ($box), o en un círculo sobre la superficie de la Tierra ($center).
En el caso del polígono ($polygon) no hay incluir dos veces el primer punto, como si hay que hacerlo en el caso de tener objetos GeoJSON.
En el caso del círculo las unidades son las mismas que las utilizadas en las coordenadas x e y, y se utiliza geometría plana para llevar a cabo los cálculos.
El uso de un índice 2d no es obligatorio en este caso, si bien debería mejorar el rendimiento.
Índices 2d. Inclusión
10:19

Índices 2d. Inclusión
2 questions

Las operaciones de intersección ($geoIntersects) que podemos hacer con pares de coordenadas x, y son tres: intersección con un punto, una línea o un polígono. Para cada una de ellas tendremos que usar un objeto GeoJSON distinto (Point, LineString, Polygon) en el campo $geometry.
En este caso la creación de un índice 2dsphere es obligatoria, ya que los datos de localiazción no están en formato GeoJSON.
Índices 2d. Intersección
09:24

Índices 2d. Intersección
1 question

A partir de la versión 2.4 de MongoDB se pueden crear índices de texto, que mejoran el rendimiento de las consultas que filtran campos de tipo texto o de tipo array de textos.
Esta funcionalidad no está activada por defecto, si bien esto cambia a partir de la versión 2.6.
Para crear un índice de tipo texto haremos db.nombre_collecion.ensureIndex( { campo : "text" } ). El índice no tiene en cuenta palabras como a, el, en,...
Preview 05:39

Índices de texto. Introducción
3 questions

Se puede especificar el lenguaje que ha de utilizar el índice, con db.colección.ensureIndex( { campo : "text" } , { default_language : "spanish" } ). El idioma por defecto es el inglés.
Podemos incluir la información de idioma dentro del propio documento. Si existe un campo language en el documento se utilizará su valor.
Si queremos que se utilice otro campo para este fin haremos db.colección.ensureIndex( { campo : "text" } , { language_override : "idioma"} ). Para ver un listado de idiomas soportados tenemos http://docs.mongodb.org/manual/reference/command/text/#text-search-languages.
Índices de texto. Lenguaje
04:04

Sólo se puede tener un índice de texto por colección, aunque puede contar con varios campos de tipo texto. Incluso hay una manera de indexar todos los campos que contengan textos, sin necesidad de saber cuáles son, con db.colección.ensureIndex( { "$**" : "text" } ).
La creación y el mantenimiento de este tipo de índices es costosa. Utilizarlos con prudencia.
Cuando se crea un índice de texto sobre varios campos, se puede otorgar distinta importancia al hecho de encontrar el término de búsqueda en cada uno de ellos. Por defecto, cada campo tiene una importancia de 1.
Índices de texto. Opciones
03:43

Se pueden crear índices compuestos con este tipo de índices, pero no pueden coexistir con índices multiclave o geoespaciales, y en el caso de que otros campos preceden al de tipo texto en el índice, para filtrar por texto tiene que haber una condición de igualdad sobre los campos que preceden al de texto.
Índices de texto. Índice Compuesto
03:20

Índices de texto. Opciones
4 questions

Para los ejemplos de búsquedas en MongoDB 2.4 vamos a usar una colección con documentos que tienen un campo tipo de 1 a 5, y otro campo texto con un número aleatorio de palabras.Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.IndicesTexto.Busquedas2.4.zip y descomprimirlo.
Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaTextos.js. Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior.
Para realizar consultas utilizando los índices de texto hay que recurrir a la ejecución de un comando, cuyo resultado es un documento que tiene un campo resultados en el que se incluye un array de documentos que cumplen el criterio de búsqueda.
Por defecto los resultados se limitan a 100 documentos y se ordenan según un cómputo de lo bien que cumplen con el criterio. Veamos algunos ejemplos de uso del parámetro búsqueda.
Para buscar los documentos que contienen las palabras café o té, pero no leche en el campo texto haremos db.colección.runCommand( "text", { search: "café té -leche" } ).
Índices de texto. Búsquedas 2.4
09:55

A partir de la versión 2.6 se debe utilizar un operador en las consultas ($text), y se recomienda no utilizar el comando que hemos visto anteriormente. La sintaxis general es db.textos.find( { $text: { $search: búsqueda, $language: idioma } } ).
En este caso no se ordenan los resultados según un cómputo de lo bien que cumplen con el criterio, y no se limitan por defecto a 100 los resultados.
Se puede obtener el cómputo de lo bien que cumplen con el criterio, o incluso ordenar los resultados por ese cómputo.
Para buscar los documentos que contienen las palabras café o té, pero no leche en el campo texto haremos db.textos.find( { $text: { $search: "café té -leche" } } ).
Índices de texto. Búsquedas 2.6
12:45

Índices de texto. Búsquedas
4 questions

A partir de la versión 2.4 de MongoDB apareció un nuevo tipo de índice, de hash. Lo que hace es calcular un hash del valor del campo indexado. No funcionan bien para búsquedas por rango de valor.
Su utilidad principal está relacionada con el particionamiento, que veremos más adelante. No se recomienda su uso con números decimales, puesto que puede obtener el mismo hash para valores decimales próximos.
Se crea un índice hash con db.colección.ensureIndex( { campo: "hashed" } ).
Índices hash
03:05

Índices hash
1 question

Hasta la versión 2.4 de MongoDB, sólo se podía utilizar un índice en cada operación, salvo en el caso de utilizar $or. A partir de la versión 2.6 MongoDB es capaz de utilizar la intersección de índices. Es decir, puede utilizar varios índices para llevar a cabo una operación.
Vamos a ver como funciona la intersección de índices con una colección que ya hemos utilizado previamente. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 2.InterseccionIndices.zip y descomprimirlo.
Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuaciones.js. Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior.
Supongamos que tenemos índices sobre los campos de tipo y puntuacion. Para recuperar los exámenes con una puntuación superior a 90, con db.puntuacion.find( { tipo : "examen" , puntuacion : { $gt : 90 } } ) MongoDB podría utilizar los dos índices y efectuar la intersección del resultado de aplicar ambos.
MongoDB puede decidir usar sólo uno de ellos. Analizará el coste de usar los dos, o uno de ellos, y decidirá cuál es el más eficiente. En la intersección de índices se puede utilizar un subconjunto cabecero de un índice compuesto.
Intersección de índices
08:19

Intersección de índices
1 question

Ya vimos que cada cierto tiempo MongoDB evalúa las alternativas que tiene para llevar a cabo una consulta. Es decir, prueba en paralelo la ejecución de la consulta con todos los índices candidatos para esa consulta y sin ellos.
Como resultado de este proceso, una de las alternativas es considerada la más adecuada, y se utiliza hasta que no vuelva a tener lugar una nueva evaluación. Esta información se almacena en la caché de planes de consulta (Query Plan Cache).
A partir de la versión 2.6 de MongoDB la ejecución de explain no elimina los planes de consulta de la operación en la caché. Además, podemos acceder a la información de la caché de planes de consulta. E incluso eliminar todos o algunos de los planes de consulta.
Caché de planes de consulta. Novedades 2.6
03:32

Podemos averiguar para qué operaciones realizadas sobre una colección existe un plan de consulta, es decir, ya se han evaluado las alternativas disponibles y se cuenta con información de cuál de ellas es la mejor.
Para hacer esto tenemos dos posibilidades: db.runCommand( { planCacheListQueryShapes: "colección" } ) ó db.colección.getPlanCache().listQueryShapes().
También podemos recuperar la información que está almacenada en la caché de planes de consulta para una determinada operación (db.colección.getPlanCache().getPlansByQuery).
O eliminar los planes de consulta de una operación (db.colección.getPlanCache().clearPlansByQuery) o de todas las que afectan a una colección (db.colección.getPlanCache().clear).
Caché de planes de consulta. Gestión
12:35

Caché de planes de consulta
2 questions

A partir de la versión 2.6 de MongoDB aparece lo que se conoce como filtros de índices. Sirven para limitar los índices que se evalúan antes de llevar a cabo una operación.
Con los filtros de índices lo que hacemos es limitar los índices que van a ser evaluados para una consulta determinada, que vendrá definida por el criterio de filtrado, la proyección, y el criterio de ordenación.
Cuando el servidor MongoDB se reinicia, lo hace sin filtros. Así que si queremos que sean permanentes, tendremos que crearlos cada vez que el servidor se reinicie.
Puesto que modifican el comportamiento estándar de MongoDB deben ser usados con cuidado. Aparece un campo nuevo al hacer un explain, filterSet. Si una operación utiliza un filtro de índices, este campo estará a true. Si no a false.
Filtros de índices
05:14

Existen una serie de comandos del shell que nos permiten gestionar los filtros de índices: planCacheListFilters, que recupera todos los filtros de índices existentes para una colección; planCacheSetFilter, que crea un filtro de índice para una colección; planCacheClearFilters, que elimina filtros de índices existentes para una colección.
Vamos a ver ejemplos de ellos con la colección de puntuaciones
Filtros de índices. Ejemplos
11:18

Filtros de índices
3 questions
+
Diseño de estructuras de datos
26 Lectures 02:52:39
En esta sección veremos cómo se afronta en MongoDB el diseño de la estructura de nuestros datos, proceso muy distinto al que habitualmente se sigue en el mundo relacional.
Veremos cómo podemos contrarrestar la ausencia las características del mundo relacional que MongoDB no proporciona.
También conoceremos cómo se almacena la información en MongoDB, y echaremos un vistazo a dos alternativas de almacenamiento que se utilizan menos (colecciones limitadas y GridFS).
Diseño de estructura de datos. Introducción
03:22

A menudo se asocia MongoDB con bases de datos no estructuradas (schemaless), pero en realidad cualquier aplicación que utilice MongoDB para almacenar la información requiere de un proceso de diseño de la base de datos.
El hecho de que los documentos de MongoDB no deban seguir una estructura rígida no significa que no la haya. Más bien deberíamos hablar de estructura flexible o dinámica.
Algunas de las partes de la estructura de datos son implícitas, mientras que otras son explícitas. Los documentos de una colección generalmente respetan una estructura, pero ésta no se ha de declarar previamente, ni se ha de seguir a rajatabla.
Los índices se crean de manera explícita, al igual que las claves de particionamiento (shard keys).
MongoDB si tiene modelo de datos
02:50

A la hora de diseñar una estructura de datos tendremos que decidir cuántas colecciones tendremos, cómo serán los documentos de cada colección, si incluimos documentos dentro de otros (embedding) o creamos una colección aparte (linking),...
Vamos a ver un poco más detenidamente lo que significa empotrar y enlazar documentos.
Diseño de estructura de datos. Decisiones
05:23

Los tres aspectos más importantes a la hora de diseñar nuestro modelo de datos son la forma en que se consultan los datos, la forma en que se particionan (sharding), y los requisitos de atomicidad.
Respecto a esto último hay que tener en cuenta que MongoDB no proporciona transacciones, sino que garantiza la atomicidad de las operaciones sólo a nivel de documento, es decir, todas las modificaciones que hagamos sobre un documento en una instrucción son atómicas.
Por esto a veces incluir documentos dentro de otros en vez de crear más colecciones, puede contrarrestar el hecho de que MongoDB no soporta transacciones.
Diseño de estructura de datos. Criterios
06:37

Diseño de estructura de datos
5 questions

En el mundo relacional el diseño de la estructura de nuestros datos se lleva a cabo generalmente normalizando. Es decir, aplicando formas normales. Habitualmente se utilizan las tres primeras.
Vemos un pequeño ejemplo de normalización con los artículos de un blog.
Los objetivos básicos de la normalización son: evitar la redundancia de los datos, minimizar el rediseño de la estructura al extender, y evitar el favorecimiento de cualquier tipo de patrón de acceso. Es decir, la forma en la que se accede a los datos no se contempla a la hora de diseñar la estructura de datos.
Normalización
07:18

El diseño del modelo de datos en MongoDB persigue unos objetivos similares a los de la normalización, salvo el último. Quizás el más importante, porque en MongoDB las forma en la que se acceden a los datos es uno de los principales factores a la hora de diseñar la estructura de datos.
En MongoDB también se ha de tratar de evitar la redundancia de datos, pero no es una obligación.
En cuanto al segundo objetivo, MongoDB favorece los cambios en la estructura de datos, ya que al no limitar la estructura de los documentos de una colección, pueden convivir en ella documentos con variadas estructuras sin causar graves problemas.
Eso sí la aplicación será la responsable de controlar si trabaja con los documentos que siguen una u otra estructura.
MongoDB y la normalización
07:05

MongoDB y la normalización
2 questions

Veamos el ejemplo de una aplicación que almacena la información de una compañía de seguros (sólo la parte de seguros, no la de reclamaciones).
Se trata de pólizas, que cubren un bien, que cubren a una o varias partes, que cuentan con una o más coberturas, que guardan información histórica de sus precios, que cuentan con uno o más contratos, y en el que intervienen uno o más de los empleados de la aseguradora.
Para las partes intervinientes probablemente usaríamos otra colección, puesto que los clientes pueden aparecer en varias pólizas, y así evitamos redundancia y posibles problemas de inconsistencia. Para los empleados también podríamos tener otra colección, por los mismos motivos que explicamos en el caso de las partes intervinientes.
Las colecciones de partes intervinientes y empleados tendrían campos para datos identificativos (nombre, apellidos, fecha nacimiento,...) y algunos más, según el caso.
Ejemplo de pólizas de seguro (1)
05:09

En el ejemplo de documento que representa una póliza, vemos que hay campos en los que se hace referencia al campo _id de otras colecciones. Es lo que se conoce en MongoDB como enlazado (linking).
En otros campos hemos incluido documentos que podrían haber estado en otras colecciones, como el bien asegurado o las coberturas. A esto se le conoce como empotrado (embedding).
¿Cuándo usar enlazado y cuándo empotrado? En general se debe recurrir al enlazado cuando el empotrado supusiera tener mucha redundancia. El empotrado permite realizar operaciones atómicas y acceder a toda la información sin echar de menos los joins.
Se puede ver el empotrado como una especie de join previo. Otra forma de entender el empotrado es como una desnormalización, en contraste con la normalización de datos tan tradicional en el mundo relacional.
Ejemplo de pólizas de seguro (2)
09:05

Al incluir el objeto bien en la colección de pólizas se podría dar cierto grado de redundancia, por ejemplo, al tener que introducir datos de coches con los mismos campos, pero no es algo que suceda muy menudo.
Respecto al enlazado, hay que subrayar que MongoDB no fuerza ningún tipo de comprobación a la hora de introducir los valores de _id de las colecciones enlazadas.
En definitiva, cada documento de la colección pólizas cuenta con gran cantidad de información que puede ser recuperada o modificada en una única consulta.
Por otro lado, podríamos haber pensado en almacenar a los intervinientes y a los empleados en una misma colección, de personas por ejemplo, y para los empleados tener algo más de información (sigue en la empresa, cuándo empezó, departamento,...).
Desde un punto de vista relacional la información de intervinientes y empleados se habría almacenado en tablas muy similares a las colecciones que aquí se han propuesto. Pero respecto a las pólizas seguramente hubiésemos acabado con varias tablas.
Ejemplo de pólizas de seguro (3)
08:19

La ausencia de joins en MongoDB se resuelve principalmente incluyendo documentos en otros. Si empotramos, y hay que consultar dos o más colecciones simultáneamente, la aplicación tendrá que encargarse de realizar el join ella misma, lo que generalmente no ofrecerá un buen rendimiento.
Si tenemos que enlazar un documento con otro, MongoDB no va a hacer ninguna comprobación respecto a si el campo utilizado para enlazar existe en la otra colección. Pero fijaros que cuando incluimos un documento en otro no hay ninguna comprobación que realizar.
Si queremos que determinados grupos de acciones sean atómicas, han de afectar a un único documento. Por eso es muy importante tener en cuenta los requisitos de atomicidad de nuestra aplicación a la hora de diseñar su modelo de datos.
Si tenemos requisitos de atomicidad que afectan a operaciones sobre documentos distintos las únicas alternativas que nos quedan son tolerar su ausencia o implementar la atomicidad de operaciones en la aplicación.
Respecto a la implementación de las transacciones en la aplicación hay un ejemplo típico de movimientos de cuentas bancarias en http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/.
Vivir sin joins ni transacciones
07:41

Vivir sin joins ni transacciones
3 questions

Supongamos el currículum de una persona. Cada curriculum pertenece a un persona, y cada persona tiene un único currículum. En este caso podríamos pensar en tener una única colección de personas.
Otra opción sería separar los datos de identificación y el currículum en dos colecciones. Con esto perderíamos la posibilidad de realizar operaciones atómicas. Si parte de la información que vamos a guardar en el currículum puede superar los 16MB, deberíamos almacenarla en otra colección.
Por otro lado, sí lo normal es que se acceda de manera separada a la información de identificación de la persona y a su curriculum, puede ser conveniente guardarlas en colecciones distintas, sobre todo si se accede más a menudo sólo a la información de identificación de la persona.
En ese caso, y si tuviésemos todo en una colección, cada vez que queremos recuperar la información de identificación de la persona, estamos trabajando con una colección en la que mayoría de información es del curriculum, y no nos es de utilidad.
Relaciones uno a uno
08:16

Ahora veamos el caso de los datos identificativos de los clientes de un gimnasio. Cada cliente vive en una ciudad, y en una ciudad pueden vivir varios clientes. Podemos tener una única colección de personas, o la anterior más una de ciudades en la que guardamos el nombre y provincia de la ciudad de cada cliente.
En el primer caso lo normal es que tengamos mucha redundancia de datos en el campo de ciudad y provincia de los clientes, ya que en cada uno de los documentos tenemos el campo ciudad y provincia.
En el segundo caso, en los documentos de la colección clientes tendremos un campo ciudad con un código o el nombre. La redundancia se ha reducido.
Si no vamos a recuperar a menudo los datos del cliente y el nombre de la ciudad y la provincia en la que vive, lo lógico sería enlazar. Así evitaremos posibles anomalías en el nombre de la ciudad y la provincia. En este caso mantener la integridad referencial entre ambas colecciones es responsabilidad de la aplicación.
Relaciones uno a varios. Gimnasio
05:52

Veamos los comentarios de un artículo de un blog. Un artículo de un blog puede tener varios comentarios, y un comentario es de un sólo artículo del blog. Es una relación de uno a varios, como en el ejemplo de los clientes del gimnasio.
Sin embargo hay algunas diferencias. En primer lugar, es muy improbable que dos comentarios distintos sean iguales, mientras que es probable que dos clientes vivan en la misma ciudad. Por lo tanto, vamos a tener muy poca redundancia.
Además el número de comentarios de un artículo de un blog no es un número muy elevado, en general, mientras que los clientes que viven en una ciudad pueden ser muchos.
Y por último al recuperar la información de un artículo del blog querremos también los comentarios de éste. Por lo tanto, en este caso lo normal sería incluir los datos de cada comentario en el documento de cada artículo del blog.
Relaciones uno a varios. Artículos de un blog
05:44

Un ejemplo adicional es el de libros de una editorial. Un libro es publicado por una editorial, y una editorial edita varios libros. En este caso volvemos a tener redundancia, ya que los datos de la editorial de un montón de libros son exactamente iguales.
Por tanto, en principio lo lógico sería enlazar. Pero, ¿en qué sentido? Es decir, ¿incluimos en cada libro un identificador de editorial, o incluimos en cada editorial un array de identificadores de libros?
El patrón de acceso debería ayudarnos a tomar una decisión, pero introducimos en este caso un nuevo factor a tener en cuenta. En el primer caso tenemos un campo editorial que es prácticamente inmutable, y aunque cambiase pasaría de ser un identificador a otro (casi lo mismo).
En el segundo caso tenemos un array de identificadores de libros que va haciéndose más grande conforme la editorial saca nuevos libros, y más pequeño si eliminamos los libros descatalogados.
En definitiva un campo que va variando, creciendo y decreciendo de tamaño. Algo que puede provocar diversos movimientos en los documentos, lo que siempre se debe intentar evitar.
Relaciones uno a varios. Libros de una editorial
06:56

El ejemplo que veremos es el de los autores de un libro. Un libro puede tener varios autores, y un autor puede escribir varios libros. En este caso no es aconsejable incluir documentos, ya que se trataría de incluir el mismo documento (autor o libro) en varios documentos (libro o autor). Hay redundancia y posibilidad de anomalías en la actualización.
En todo caso, incluir documentos no es algo totalmente descartable. Si se decide enlazar, para decidir en qué sentido hacerlo tendremos que pensar en los patrones de acceso de la aplicación, y en lo que comentamos previamente sobre los movimientos de documentos.
En resumen, el mayor beneficio del empotrado frente al enlazado es la mejora de rendimiento. Recuperamos toda la información necesaria consultando una única colección en una única operación.
Uno de los motivos por los que el enlazado y el empotrado funcionan bien en MongoDB es por la existencia de los índices multiclave.
Relaciones varios a varios
10:33

Relaciones en MongoDB
5 questions

Vamos a trabajar con una estructura de datos habitual: la estructura de árbol. Pongamos por caso la categoría de libros de Informática. Como primera opción vamos a probar almacenando en cada categoría una referencia a la categoría padre.
Esta opción simplifica la forma de crear y modificar el árbol, pero requiere de varias consultas para obtener una rama del árbol. Además una categoría no puede tener más de un padre.
Ejemplo de estructura de árbol. Padre
06:10

Vamos a trabajar con una estructura de datos habitual: la estructura de árbol. Pongamos por caso la categoría de libros de Informática. Como segunda opción vamos a probar a almacenar en cada categoría un array con todas las referencias de las categorías hijas.
Esta opción también requiere de varias consultas para obtener una rama del árbol. En este caso una categoría puede tener más de un padre.
Ejemplo de estructura de árbol. Hijos
05:28

Vamos a trabajar con una estructura de datos habitual: la estructura de árbol. Pongamos por caso la categoría de libros de Informática. Como tercera opción vamos a probar a almacenar en cada categoría un array con todas las referencias de las categorías de su árbol por orden jerárquico.
Esta opción es muy útil para trabajar con subárboles. Es bastante eficiente para averiguar los descendientes y los ancestros de una categoría.
Ejemplo de estructura de árbol. Array de ancestros
04:57

Vamos a trabajar con una estructura de datos habitual: la estructura de árbol. Pongamos por caso la categoría de libros de Informática. Como cuarta y última opción vamos a probar a almacenar en cada categoría una cadena con todas las referencias de las categorías de su árbol por orden jerárquico, separadas por una coma.
Esta opción es muy útil para trabajar con subárboles, siendo algo más rápida que la anterior. Es bastante eficiente para averiguar los descendientes y los ancestros de una categoría.
Ejemplo de estructura de árbol. Cadena de ancestros
05:40

En MongoDB los documentos se guardan en disco alojados en registros. Cada documento ocupa un registro. El tamaño del registro puede ser mayor que el del documento, lo que le permitiría crecer sin tener que cambiar de registro (moverse).
En MongoDB hay que tratar de minimizar los movimientos de documentos. Los registros se almacenan de manera contigua en los archivos del disco de la colección.
Las colecciones se agrupan en bases de datos. Cuando en la colección de una base de datos tiene lugar una operación de escritura, se bloquea toda la base de datos, y no se pueden realizar otras operaciones mientras tanto.
Preview 04:44

La forma de decidir el tamaño del registro viene dada por el tipo de estrategia que escojamos. Existen dos.
La primera intenta que el espacio extra del que dispone el documento sea el menor posible (Exact Fit Allocation). Intenta adaptarse al tamaño del documento, más un pequeño espacio extra para posteriores modificaciones. Es la que se usaba por defecto en la versión 2.4 de MongoDB.
La segunda restringe el tamaño del registro a una potencia de 2, con un mínimo de 32 bytes (Use Power Of 2 Sizes). Esto hace que para MongoDB sea más fácil reusar registros existentes, lo que puede disminuir la fragmentación. Además reduce el número de operaciones que provocan movimientos.
Aunque usa más espacio extra, y por tanto, las colecciones ocupan más en disco. En la versión 2.6 ha pasado a ser la estrategia por defecto.
Estrategias de almacenamiento
07:37

En versiones 2.2 y 2.4 de MongoDB, si queremos que una colección use la estrategia Use Power Of 2 Sizes, tendremos que hacer db.runCommand( { collMod: "colección", usePowerOf2Sizes : true } ). O podemos hacerlo al crearla, con db.createCollection("colección", { usePowerOf2Sizes : true } ).
En la versión 2.6 podemos hacer que todas las colecciones vuelvan a utilizar la estrategia Exact Fit Allocation con db.getSiblingDB('admin').runCommand( { setParameter : 1, newCollectionsUsePowerOf2Sizes : false } ) o con mongod --setParameter newCollectionsUsePowerOf2Sizes=false al arrancar el servidor.
Si queremos que una colección la utilice podemos hacer db.runCommand( { collMod: "colección", usePowerOf2Sizes : false } ), o db.createCollection("colección", { usePowerOf2Sizes : false } ).
Estrategias de almacenamiento. Cambios
05:51

Almacenamiento en MongoDB
6 questions

Las colecciones limitadas (capped collections) tienen un tamaño fijo y se crean de manera explícita. Desde el principio se ocupa todo el tamaño de la colección, aunque no haya documentos suficientes. También existe la posibilidad de limitar el número máximo de documentos.
No podemos borrar documentos, ni efectuar actualizaciones que hagan que el documento crezca, ni particionar estas colecciones. Las inserciones se guardan en el disco en el mismo orden en el que se hicieron.
De este modo la inserción y la consulta de documentos es más rápida. Cuando están llenas y llega una nueva inserción, se eliminan de manera automática y por orden decreciente de antigüedad, tantos documentos como sea necesario para llevarla a cabo.
Podemos convertir a limitada una colección o averiguar si una colección lo es.
Colecciones limitadas
10:33

Colecciones limitadas
2 questions

GridFS nos permite guardar objetos grandes en MongoDB, a pesar de la limitación de 16MB que tiene un documento BSON. GridFS divide el objeto grande en trozos de 256KB por defecto (255KB desde la versión 2.4.10).
Utiliza dos colecciones, una para almacenar los trozos (fs.chunks) y otra para guardar información acerca de dónde guarda cada trozo (fs.files).
La colección de trozos tiene un índice sobre los campos files_id y n. El primero hace referencia al identificador del fichero, mientras que el segundo hace referencia al número de secuencia del trozo.
No se recomienda su uso si hay que actualizar el contenido completo de los ficheros de manera atómica, ya que cada trozo del fichero estará en un documento de la colección fs.chunks.
GridFS
06:17

MongoDB cuenta con una utilidad, mongofiles, que nos permite trabajar desde la consola con GridFS. Podemos guardar archivos, recuperar un listado de archivos o los propios archivos, e incluso eliminar archivos.
En la consola de MongoDB, para consultar lo que se ha guardado en la colección files haremos db.fs.files.find().pretty(). Para consultar lo que tenemos en la colección chunks haremos db.fs.chunks.findOne( { } , { data : 0 } ) para ver la información de un trozo, y db.fs.chunks.find().count() para ver cuántos trozos tenemos.
GridFS y mongofiles
07:24

En el archivo 3.GridFS.NodeJS.zip tenéis el código de un ejemplo NodeJS que utiliza GridFS. Este ejemplo no es adecuado para trabajar con archivos muy grandes podemos tener problemas con la memoria, ya que se cargan completos en ella.
En estos casos utilizaremos otras soluciones. En el siguiente enlace tenéis un ejemplo http://mongodb.github.io/node-mongodb-native/api-articles/nodekoarticle2.html#advanced-gridfs-or-how-not-to-run-out-of-memory
GridFS y NodeJS
07:48

GridFS
5 questions
+
Agregación
28 Lectures 03:10:41
En MongoDB existen cuatro alternativas para realizar este tipo de operaciones. La menos potente de todas es la agregación mediante operaciones de propósito simple. No vamos a profundizar más ya que apenas se utiliza (versiones anteriores a la 2.2).
El sistema de agregación de MongoDB, introducido en la versión 2.2, funciona con el modelo de tuberías, de modo que los documentos de una única colección pasan a través de varias fases, que los van modificando, filtrando o agrupando.
MongoDB incluye una implementación de MapReduce que también trabaja sobre los documentos de una única colección. A groso modo podríamos decir que MapReduce hace lo mismo que el sistema de agregación de MongoDB, y además puede hacer operaciones más complejas.
A parte de la implementación que MongoDB incorpora de MapReduce, también existe la posibilidad de que MongoDB actúe como entrada o salida de Hadoop, una implementación de código abierto de MapReduce mantenida por Apache.
Alternativas de agregación en MongoDB
06:09

En general la recomendación de MongoDB es empezar con el sistema de agregación. Si la agregación que queremos hacer no se puede expresar fácilmente con el sistema de agregación, deberíamos probar con la implementación MapReduce de MongoDB.
Si tenemos que hacer un uso intensivo de agregación deberíamos pensar en el conector MongoDB para Hadoop. Este último es el único que realmente puede trabajar de manera paralela, puesto que MapReduce de MongoDB se ejecuta en un único hilo.
En producción y para uso intensivo de MapReduce, Hadoop debe ser la primera opción.
¿Qué alternativa de agregación elegir?
03:04

Alternativas de agregación en MongoDB
3 questions

Para los primeros ejemplos vamos a utilizar una colección de datos de códigos postales de USA. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 4.SistemaAgregacion.IntroduccionSintaxis.zip y descomprimirlo. Importar el archivo zips.json con mongoimport.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Podéis comprobar que la colección en la que habéis importado los datos tiene 29467 documentos.
Empezaremos con un ejemplo básico que agrupa los códigos postales por estado, y calcula la suma de las poblaciones. En este ejemplo sólo existe una fase, la de agrupación. Fijaros que cuando nos referimos al valor de un campo escribimos el campo entre comillas y con un signo de dólar delante.
El resultado es un único documento en el que hay un campo de tipo array, result, que contiene la información solicitada, por lo tanto el resultado tiene el mismo límite que cualquier documento de una colección, 16MB.
Sistema de agregación. Introducción y sintaxis
08:27

A partir de la versión 2.6 el uso del sistema de la agregación cambia. El resultado es un cursor en vez de un documento, con lo que ya no hay límite de 16MB para el conjunto del resultado, si no para cada uno de los resultados. Además se pueden indicar tres opciones: explain, allowDiskUse y batchSize.
Explain sirve para mostrar información de cómo se llevó a cabo la operación, allowDiskUse permite utilizar ficheros temporales en el disco para llevar a cabo la operación, y batchSize especifica el tamaño del primer lote de datos del cursor.
La opción allowDiskUse nos permite salvar uno de los límites del sistema de agregación. Sólo puede utilizar el 10% de la memoria para llevar a cabo las operaciones de las etapas. Si activamos esta opción, podemos utilizar ficheros temporales del disco para esto.
Sistema de agregación. Introducción y sintaxis en 2.6
04:52

Las operaciones del sistema de agregación pueden tener varias etapas o fases. Cada una de ellas consta de un operador y de una expresión. En el ejemplo que hemos visto el operador es $group, y la expresión { _id : "$state" , poblacionTotal : { $sum : "$pop" } }.
Observemos que la etapa completa se expresa como un documento, al igual que la expresión. Dentro de la expresión tenemos un operador de expresión, $sum.
Cada uno de los documentos de la colección va pasando por la primera etapa. Ésta filtra, transforma o agrupa, y los documentos resultado pasan a la segunda etapa. Ésta filtra, transforma o agrupa, y los documentos resultado pasan a la tercera etapa. Y así sucesivamente.
Etapas, expresiones, operadores,...
03:05

Los operadores de etapa son: $project (proyección), $match (filtrado), $group (agrupado), $sort (ordenación), $limit (limitación), $skip (salto), $unwind (explosión de arrays) y $geoNear (geolocalización).
A partir de la versión 2.6 se añaden 2 más: $out, sirve para guardar los resultados directamente en una colección. Debe ser la última etapa; y $redact, sirve para mantener o quitar los subdocumentos de cierto nivel de los documentos.
Salvo los operadores de etapa que están restringidos a la primera o última etapa, el resto pueden aparecen en distintas etapas, y en cualquier posición.
Los operadores de expresión que más utilizaremos serán los del operador de etapa $group. Existen otros tipos de operadores de expresión, aritméticos, de comparación, booleanos, de cadena,...
Operadores de etapa
05:25

Sistema de agregación. Introducción y sintaxis
5 questions

Vamos a ver sobre todos los operadores de expresión del operador de etapa $group. Para los ejemplos vamos a utilizar la colección de códigos postales de USA.
Ya vimos anteriormente el operador $sum. Supongamos que ahora queremos conocer la población media de las ciudades por estado. Usaríamos el operador $avg. Si agrupamos sólo por estado estamos calculando la media de población de los códigos postales de cada estado.
Para calcular realmente la media de las ciudades por estado tendríamos que hacer dos pasos. Primero agrupar los documentos por cada ciudad y estado (para evitar ciudades que pueden estar en dos estados), y luego agrupar por estado.
Operadores de expresión de agrupación (1)
06:51

Para averiguar la menor población de un código postal para cada estado usaríamos el operador $min, mientras que para averiguar la mayor población de un código postal para cada estado usaríamos el operador $max.
En los dos casos anteriores no es posible obtener el valor de otros campos, como por ejemplo el nombre de la ciudad. Para conseguir esto tendremos que recurrir a otro tipo de operadores de etapa ($sort) que veremos más adelante.
Para finalizar con los operadores de $group vamos a ver un par de operadores de expresión relacionados con los arrays, $push y $addToset.
Operadores de expresión de agrupación (2)
05:53

Operadores de expresión de agrupación
3 questions

Existen muchos otros operadores que podemos utilizar en la expresión de cada etapa. Por ejemplo, los operadores booleanos $and, $or y $not.
Los tres esperan que se les pasen valores booleanos, si no los convierten (null, undefined, y 0 son false, mientras que son true los valores númericos distintos al cero, y el resto de tipos, como cadenas, fechas y objetos).
Los operadores $and y $or aceptan un array, y devuelven true si todos o alguno de ellos son true. El operador $not invierte lo que se le pase.
También tenemos los operadores de comparación, que aceptan una array con dos valores, y que comparan sus valores. Son $cmp, $eq, $gt, $gte, $lt, $lte y $ne.
Todos devuelven true o false, excepto $cmp que devuelve un número negativo si el primer valor es menor que el segundo, un número positivo si el primer valor es mayor que el segundo, y un cero si son iguales.
Operadores de expresión. Booleanos y de comparación
08:19

Los operadores aritméticos son cinco: $add, $multiply, $divide, $mod y $subtract. Todos esperan recibir un array de valores numéricos, sobre los que realizan la operación matemática.
La única diferencia es que los tres últimos esperan un array de sólo dos elementos, mientras que los dos primeros pueden trabajar con arrays de tamaño indefinido.
Operadores de expresión. Aritméticos
04:09

Operadores específicos de valores de texto hay también cinco: $concat, $strcasecmp, $substr, $toLower y $toUpper. Todos esperan un array.
Operadores de expresión. Cadenas de texto
03:26

Hay diez operadores para extraer cada una de las partes de los valores de tipo fecha. Son $dayOfYear, $dayOfMonth, $dayOfWeek, $year, $month, $week, $hour, $minute, $second y $millisecond. Para este ejemplo vamos a utilizar una colección de datos de un gimnasio que vimos en temas anteriores.
Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 4.OperadoresExpresion.Fecha.zip y descomprimirlo. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPreferencias.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección preferencias y luego la alimenta con 2000 documentos (con preferencias y fechas aleatorias).
Vamos a calcular el número de clientes dados de alta en cada mes como ejemplo.
Preview 04:43

Operadores de expresión (1)
4 questions

Respecto a los operadores condicionales, existen dos: $cond y $ifNull. El primero recibe un array con tres expresiones. Evalúa la primera, y si resulta true devuelve la segunda expresión. Si resulta false devuelve la tercera expresión.
El segundo operador condicional recibe un array con dos expresiones. Evalúa la primera, y si resulta un valor no nulo devuelve esta expresión. En caso contrario devuelve la segunda expresión.
Vemos un ejemplo en el que calculamos la media de los buzones que tiene cada ciudad por estado. A cada código postal le corresponde un buzón por cada 1000 habitantes. Cada código postal tiene 1 buzón como mínimo.
No hemos tenido en cuenta que si la población de un código postal es mayor de 1000, estamos sumando un valor no entero de buzones.
Operadores de expresión. Condicionales
06:40

A partir de la versión 2.6 aparecen los operadores de conjunto, ($setEquals, $setIntersection, $setDifference, $setUnion, $setIsSubset, $anyElementTrue, $allElementsTrue), que reciben uno o más arrays y realizan operaciones con ellos.
También son de la versión 2.6 los operadores de array, aunque de momento sólo existe $size, que cuenta el número de elementos de un array.
Operadores de expresión. Conjuntos y arrays
03:13

Los operadores de proyección también aparecen en la versión 2.6 de MongoDB. Tenemos tres: $map, $let y $literal. Se pueden utilizar en las etapas de proyección ($project), agrupado ($group) y redactado ($redact).
El primero sirve para aplicar una expresión a todos los elementos de un array. El segundo nos permite utilizar variables. Y el tercero permite evitar que el sistema de agregación intérprete un objeto, muy útil para trabajar con valores de campo que incluyen el dólar por ejemplo.
Operadores de expresión. Proyección
12:54

Operadores de expresión (2)
4 questions

$project sirve para transformar cada documento que pasa por la etapa. Es útil para quitar campos que no se van a utilizar, acelerando la operación. También se puede utilizar para cambiar el nombre de campos o para modificarlos.
$match sirve para filtrar los documentos que pasan a la siguiente etapa. Si lo ponemos en la primera etapa puede beneficiarse del uso de los índices, y además reducimos el número de documentos que pasan al resto de etapas.
La expresión del operador $match es un documento que se utiliza igual que en la consulta de documentos con db.find( criterio ).
$group, como ya hemos visto en algunos ejemplos, sirve para agrupar los documentos y realizar cálculos.
Operadores de etapa. $project, $match y $group
07:26

$sort sirve para ordenar los documentos de la etapa anterior. Se utiliza la misma sintaxis que cuando ordenamos documentos en una operación de lectura.
$limit sirve para limitar el número de documentos que pasan a la siguiente etapa. Muy útil tras una etapa de ordenación.
$skip sirve para no pasar a la siguiente etapa los primeros documentos. Si alteramos el orden de las etapas de skip y limit, el resultado cambia. No es como cuando utilizamos esto en una consulta del tipo db.zips.find( criterio ).skip( 4 ).limit( 2 ), dónde el orden no afectaba. Aquí sí que afecta el orden.
Operadores de etapa. $sort, $limit y $skip
07:11

Operadores de etapa (1)
2 questions

Los operadores $first y $last no tienen mucho sentido si no se utilizan tras una etapa de ordenación ($sort). Son útiles si queremos recuperar información adicional a la calculada. Por ejemplo, averiguar la ciudad de cada estado que tiene mayor o menor población.
Operadores de etapa. $first y $last
07:19

$unwind sirve para trabajar con los elementos de un array, creando una copia del documento para cada elemento. En ocasiones es necesario deshacer los efectos de un unwind. Para ello hay que utilizar una etapa group inmediatamente después de la de unwind.
Operadores de etapa. $unwind
09:14

$geoNear sirve para ordenar los documentos por la proximidad a un punto. Debe ser la primera etapa, y la colección debe tener un índice geoespacial.
Por defecto devuelve los 100 primeros resultados, salvo que se indique lo contrario con el parámetro limit. Se ha de indicar al menos el nombre del campo en el que se pondrá la distancia al punto dado.
Operadores de etapa. $geoNear
06:55

A partir de la versión 2.6 se añaden dos operadores de etapa. $out sirve para guardar los resultados directamente en una colección. Debe ser la última etapa. Su sintaxis es { $out : "nombre_coleccion" }. Si no existe la colección se crea, si existe se reemplaza atómicamente con los resultados de la agregación.
La colección destino no puede ser limitada ni estar particionada, si bien la colección sobre las que se realizan las operaciones de agregación si puede estar particionada.
$redact sirve para mantener o quitar los subdocumentos de cierto nivel de los documentos.
Operadores de etapa. $out y $redact
05:33

Vamos a ver un par de ejemplos utilizando NodeJS. En el primero utilizamos la sintaxis de la versión 2.4 de MongoDB. En el segundo caso la sintaxis de la versión 2.6. Tened en cuenta que para que funcione el segundo caso quizás debáis actualizar el módulo NodeJS de MongoDB.
El código de los ejemplos los tenéis en el archivo 4.OperadoresEtapas.EjemplosNodeJS.zip
Operadores de etapa. Ejemplos NodeJS
06:20

Operadores de etapa (2)
3 questions

Hay una cierta correspondencia entre SQL y el sistema de agregación. Algunos de los operadores de este último tienen la misma funcionalidad que algunas de las opciones de SQL. Por ejemplo, una etapa de filtrado ($match) se corresponde con lo que hace un WHERE en una sentencia SQL.
Equivalencias entre SQL y el sistema de agregación de MongoDB
06:42

Equivalencias entre SQL y el sistema de agregación de MongoDB
1 question

MapReduce puede resolver un problema utilizando procesamiento paralelo y distribuido, siempre que podamos descomponer el citado problema en una operación Map y otra Reduce.
Una función Map emite un par clave valor por cada documento. Para calcular la clave y el valor a emitir se pueden realizar varias operaciones (sumas, concatenaciones, multiplicaciones,...), que se aplicarán a todos los documentos a procesar.
Una función Reduce obtiene unos valores a partir de todos los valores que comparten clave, como por ejemplo la media, el máximo, la suma,... Una vez que reducimos un problema a una función Map y a otra función Reduce, teóricamente seremos capaces de resolver el problema aplicando procesamiento paralelo y distribuido.
Por cada dato que procesamos en la función Map obtenemos un dato, mientras que en la función Reduce obtenemos uno o varios datos, resultado de agregar de alguna manera todos los datos obtenidos tras aplicar la función Map.
MapReduce
04:57

El MapReduce de MongoDB admite funciones JavaScript para Map y para Reduce. Vemos un ejemplo con la colección del gimnasio. Averiguar el número de veces que cada deporte ha sido incluido en las preferencias de un cliente.
La función Map no puede acceder a la base de datos, ni afectar a nada que no esté en la propia función. Puede llamar a la función emit 0, 1 ó varias veces por cada documento. Dentro de la función Map nos referiremos al documento con this. Cada función emit tiene un límite de 8MB, la mitad del límite de documento BSON.
La función Reduce recibe un valor de preferencia y un array de valores. Al igual que la función map no puede acceder a la base de datos, ni afectar a nada que no esté en la propia función.
En el resultado del comando mapReduce de MongoDB, es interesante revisar la información que se nos proporciona en el campo counts del resultado. El valor de reduce es el número de veces que se ha ejecutado la función reduce.
Preview 11:04

El parámetro out es para indicar a dónde enviar los resultados. Para filtrar la colección antes de empezar con MapReduce utilizamos el parámetro query.
El parámetro sort se aplica a los documentos de la colección, igual que limit. Si ordenamos los datos de entrada por la clave que utilizaremos en el emit, se pueden reducir las veces que se ejecuta la función reduce.
Para ejecutar una función tras terminar podemos especificar el parámetro finalize. Para utilizar variables globales dentro de las funciones map, reduce y finalize las incluiremos en el parámetro scope.
Si queremos que los datos que van de la función map a la reduce se conviertan a formato BSON utilizaremos jsMode : false, que por defecto está a false. Y para ocultar la información sobre lo que duró la operación indicamos verbose : false, que por defecto está a true.
Sintaxis de MapReduce
04:06

En ejemplos reales será necesario ir haciendo pruebas hasta conseguir el resultado deseado. Para ello será necesario ir probando por separado las funciones map y reduce. Para probar la función map crearemos una función emit que simule el comportamiento real de emit.
En cuanto a la función Reduce, tenemos que comprobar tres cosas: devuelve un valor del mismo tipo que el de los elementos del parámetro valores que recibe; devuelve lo mismo independientemente del orden de los elementos del array que recibe; devuelve lo mismo independientemente de cuántas veces sea llamada para una clave.
Depurando las funciones Map y Reduce
12:27

Vamos a hacer otro ejemplo con una colección de datos de puntuaciones. Si queréis utilizar la colección en vuestro entorno de trabajo podéis descargar el archivo 4.OtroEjemploMapReduce.zip y descomprimirlo. Luego ejecutáis mongo localhost:vuestroPuerto --shell ruta/cargaPuntuaciones3.js.
Prestad atención a utilizar el puerto en el que escucha vuestra instancia de MongoDB y la ruta en la que habéis descargado el archivo anterior. Si le echáis un vistazo veréis que cambia de base de datos, vacía la colección puntuaciones3 y luego la alimenta con 50000 documentos (con puntuaciones aleatorias).
Calculemos la media de las puntuaciones por tipo de prueba, utilizando MapReduce.
Otro ejemplo de MapReduce
14:17

MapReduce
2 questions
+
Fin del curso
1 Lecture 04:45
Fin del curso
04:45
About the Instructor
José Antonio Sánchez Ortiz
4.0 Average rating
99 Reviews
628 Students
2 Courses
Programador web y formador técnico

Ingeniero Superior de Telecomunicaciones, casi desde los inicios de mi vida laboral (finales de los 90) me especialice en acceder a bases de datos desde Internet, lo que hoy probablemente se conoce más como programador web.

Fundamentalmente he utilizado la plataforma LAMP, aunque en los últimos años estoy incorporando nuevas tecnologías a mi curriculum (Nginx, MongoDB, NodeJS,...).

También he impartido cursos relacionados con la informática (programación de aplicaciones, office, internet,...)