MongoDB en Castellano josebyte Este libro está a la venta en http://leanpub.com/mo http://leanpub.com/mongodbcastellano ngodbcastellano Esta versión se publicó en 2017-01-16
This is a Leanpub a Leanpub book. book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean process. Lean Publishing is Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get reader feedback, pivot until you have the right book and build traction once you do.
This work is licensed under a Creative a Creative Commons Attribution-No Attribution-NonCommercial nCommercial 3.0 Unported License
Índice general Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
Introducción a MongoDB . Un poco de historia . . ¿Qué es MongoDB? . . Documentos JSON . . . BSON . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
2 2 2 4 5
Instalación . . . . . . . . . Instalación en Windows Instalación en MAC . . Instalación en Linux . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
8 8 8 9
Mongo Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 CRUD . . . . . . . . Insert . . . . . . update . . . . . save . . . . . . . find y findOne . remove . . . . . findAndModify
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. 12 . 12 . 13 . 14 . 15 . 16 . 16
Operadores Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Operadores especiales: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Modelado de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Índices . . . . . . . . . . . . . . . Introducción . . . . . . . . . . Consideraciones . . . . . . . . Ver indices . . . . . . . . . . . Funcionamiento de los índices Crear indices . . . . . . . . . . mongotop . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. 21 . 21 . 21 . 21 . 22 . 22 . 24
ÍNDICE GENERAL
mongostat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
Agregation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 ReplicaSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Sharding . . . . . . . . . . . . . . . . . . . . Como elegir una shard-key correctamente nte Configurar shard-key . . . . . . . . . . . Añadir un shard al cluster . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
29 30 30 30
Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Agradecimientos Me llamo Joseba llamo Joseba Madrigal¹, Madrigal¹, soy graduado en informática además de una persona curiosa y analítica, me encanta descubrir nuevas tecnologías y ayudar a las personas de mi entorno, por ello he dedicado un par de meses a escribir este libro que espero ayude a la gente a profesionalizarse en MongoDB. El libro está escrito escrito para programado programadores res con interés interés en utilizar utilizar MongoDB MongoDB a un nivel profesional profesional.. El motivo de escribir este libro es que cuando intente realizar el salto del mundo SQL, en el cual me encontraba muy cómodo, no encontré ninguna documentación en Español y aunque todo buen desarrollador debe tener buen nivel de inglés, siempre es más cómodo leer en la lengua materna. Había pasado muchos años trabajando con Oracle PL-SQL y más de los que me gustaría trabajando con MYSQL hasta que entre en “Tapquo S.L.” y conocí más de cerca el mundo no-sql. Fue entonces cuando me apunté a los cursos de MongoDB-University y comencé a apreciar las virtudes de este mundo no-sql tan desconocido para mí. En apenas 3 meses había logrado la certificación oficial de MongoDb tanto de sus cursos como en su examen, por lo que me di cuenta de que la curva de aprendizaje es realmente rápida y buena, por consiguiente quería hacerla aún mejor para todos los hispanohablantes que quieran profesionalizarse en MongoDB. Escribí este libro en mis ratos libres, es difícil encontrar un rato libre cuando tienes una vida con un trabajo a jornada completa, impartes clases después de la jornada de trabajo, estudias, tienes familia, novia y amigos. Estas líneas no hubieran sido posibles sin el apoyo incondicional de todo mi entorno, desde aquí me gustaría agradecer a todos su comprensión y sus ánimos. A toda mi familia, pero en especial a mi hermano Aitor, por ayudarme a mejorar mi inglés, apoyarme, animarme y además hacer la revisión final del libro. A mi novia Katy agredezco su paciencia, aguantarme en los buenos y los malos momentos y por permitirme ponerme en el ordenador para escribir pese a que no le guste verme delante del PC. A mis amigos les agradezco que me ayuden a desconectar, lo cual es imprescindible de vez en cuando. A todos ellos les estaré eternamente agradecido por apoyarme siempre en todas mis decisiones. Y como no, gracias a ti por descargar este libro, espero que sea de tu agrado. ¹http://www.josebamadrigal.com
Introducción a MongoDB Un poco de historia Actualmente se escucha hablar de BigData, pero antes de comenzar hablando de grandes cantidades de datos es mejor empezar por el origen, ¿cuál es el motivo de la existencia de bases de datos para Big Data? Desde el origen de la informática ha existido la necesidad de almacenar información de forma permanente. Con el término permanente se hace alusión a datos almacenados en un medio físico como un disco duro ,(la memoria RAM no es almacenamiento permanente), la cual puede ser leída posteriormente incluso despues de apagar y encender el equipo. Inicialmente se guardaban los datos en ficheros de texto, pero pronto surgieron limitaciones, es un método poco eficaz, ¿qué ocurre si cambiamos la estructura de los datos? ¿y si cambiamos algunos datos? ¿inconsistencias?… Por ello surgiero surgieronn las bases de datos histórica históricass como las jerárquic jerárquicas, as, en red o transacci transaccionale onales. s. Estas bases de datos se siguen estudiando actualmente en las universidades pero ya no son utilizadas debido a sus limitaciones: Complejidad, duplicidad de registros, Integridad referencial, (No existe garantía de que un registro hijo esté relacionado con un registro padre válido), Desnormalización… Debido a esas limitaciones surgieron las bases de datos que se utilizan actualmente. Existen tres tipos de bases de datos: • Bases de datos relacionales: relacionales: Hasta la actualidad son las más usadas, utilizan utilizan SQL. Por ejemplo: Oracle, MS SQL Server, MySQL o MariaDB son bases de datos relacionales. • Bases de datos orientadas a objetos: Se han diseñado para trabajar bien en conjunción con lenguajes de programación orientados a objetos como Java, C#, Visual Basic.NET y C++. (No están muy extendidas en la actualidad.) • Bases de datos no-relacionales: no-relacionales: No utilizan lenguaje lenguaje SQL y están orientadas orientadas a la escalabilidad, por ejemplo MongoDB.
¿Qué es MongoDB? MongoDB es una base de datos no-relacional de documentos JSON y de código abierto escrito en C++, que proporciona alto rendimiento, alta disponibilidad y escalabilidad automática. El concepto de escalabilidad está totalmente ligado con “Big data” debido a que cuando se trabaja con grandes cantidades de datos, en otros tipos de bases de datos es complejo y costoso de gestionar. gestionar. Las bases de datos como MongoDb proporcionan escalabilidad automática, lo cual hace que esta base de datos sea idonea para grandes cantidades crecientes de información.
Introducción a MongoDB
3
El desarrollo de MongoDB comenzó en el año 2007 por la empresa 10gen3, publicando una versión final en el 2009 y actualmente se encuentra en la versión 3.0. Por lo tanto hemos mencionado que MongoDB es una base de datos escalable, no-relacional y orientada a documentos JSON(BSON), pero ¿qué significa no-relacional? y ¿documentos JSON(BSON)?
No-relacional No-relacional es un término nuevo que se aplica a todas las bases de datos que no son relacionales. Este tipo de base de datos también son conocidas como “no-SQL” o “Big Data”. MongoDB tiene las siguientes características no-relacionales: • No-SQL. • No tiene JOINs. • No tiene esquema. • Escala horizontalmente. • No tiene transacciones atómicas para multiples documentos.
No-SQL MongoDB no usa SQL como lenguaje de consultas, en su lugar dispone de una serie de métodos en JavaScript que permiten realizar consultas y operaciones.
No tiene JOINs En MongoDB no se puede hacer una relación entre dos colecciones, no existen las “join” del mundo SQL. La razón es que MongoDB está orientado a ser escalable y las join de las bases de datos relacionales escalan muy mal.
Sin esquema Una misma colección (en sql: s ql: “colección”==”tabla”) de documentos puede contener documentos con distinto formato, a esto se le llama “schemeless” o “sin esquema”. Es decir podremos tener ,por ejemplo, una colección de usuarios en donde guardemos datos diferentes para cada usuario. A esa capacidad le llamamos polimorfismo.
Introducción a MongoDB
4
Escalabilidad horizontal Uno de los motivos más importantes por el que se han creado las bases de datos no-relacionales es por la escalabilidad. Actualmente cada vez más nos encontramos con gran cantidad de datos en diferentes servidores. Las bases de datos relacionales son lentas y poco escalables en esos casos, no están pensadas para que la información almacenada sea muy grande y se encuentre distribuida, por ello ha surgido MongoDB. Este sistema de base de datos tiene la capacidad de escalar horizontalmente correcta y fácilmente sin penalización. Un sistema escala horizontalmente bien si al agregar más nodos al mismo, el rendimiento de éste mejora. Quizá ahora entiendas un poco mejor el término que comentamos anteriormente que se usa para estas bases de datos, están diseñadas para grandes cantidades de información, por ese motivo son conocidas también como bases de datos de “Big Data”.
Sin transacciones multi-documento MongoDB solo garantiza atomicidad en el propio documento. ¿Que es la atomicidad? Según Wikipedia: “La atomicidad es la propiedad que asegura que una operación se ha realizado o no, y por lo tanto ante un fallo del sistema no puede quedar a medias”. Imaginemos que estamos desarrollando la aplicación de un banco, dispondremos de diferentes cuen cuenta tass para para cada cada usua usuari rioo y exis existi tirá ránn tran transf sfer eren enci cias as de dine dinero ro de una una cuen cuenta ta a otra otra.. Las Las base basess de dato datoss relacionales aseguran que si solicitamos restar de una cuenta y añadir a otra ésta sea una operación atómica que no puede quedar a medias, o se hacen las dos operaciones(resta de una cuenta y suma a la otra) o no se hace ninguna. En la realidad, las bases de datos no se encuentran en un mismo sistema por lo que en las bases de datos relacionales también es necesario controlar la atomicidad si llevamos este caso a la vida real. En MongoDB solo las operaciones sobre un documento son atómicas, por lo que hay que tomar medidas en el código por ejemplo mediante la creación de un “semáforo” para resolver este tipo de problemas.
Documentos JSON MongoDB está orientada a documentos en “JavaScript Object Notation” (JSON), por lo que almacenamos documentos en en lugar de “registros” o “filas”. Un ejemplo de un documento JSON puede ser: 1
{"name" "name": : "Joseba", "Joseba", "surname": "surname": "Madrigal"} "Madrigal"}
Un documento JSON es un documento clave-valor. En el ejemplo anterior la clave “name” contiene el valor “Joseba” y la clave “surname” contiene el valor “Madrigal”. Un ejemplo más complejo de un JSON:
Introducción a MongoDB 1
{
2
"name" : "Joseba", "Joseba",
3
"surname" : "Madrigal", "Madrigal",
4
"age" : 28 28, ,
5
"skills" : ["javascript" "javascript", , "MongoDB", "MongoDB", "jquery", "jquery", "angularjs", "angularjs", "php"], "php"],
6
"address" : {
7
"street_address": "23 Elm Dri "street_address": Drive" ve" ,
8
"city": "Palo "city": "Palo Alto" Alto", ,
9
"state": "California", "state": "California",
10
"zipcode": "94305" "zipcode":
11 12
5
} }
Más adelante comentaremos los tipos de datos de JSON y veremos que internamente se almacenan BSONs. Existe un límite de 16MB por documento en MongoDB. En 16MB cabe mucha información y si tuviésemo tuviésemoss que introducir introducir más podríamos partir esa informaci información ón en varias varias coleccione colecciones. s. Para usar documentos más grandes MongoDB proporciona GridFS. JSON es un estándar y puedes saber más en JSON.org² en JSON.org²
BSON Pese a que nosotros a priori en MongoDB usemos documentos en formato JSON, MongoDB trabaja internamente con BSON (JSON Binario). Un BSON no es más que la representación binaria de un documento JSON. Puedes ver más información en BSONspec³ BSONspec³.. BSON extiende del modelo JSON para proporcionar “tipos de datos” para una correcta codificacion y decodificación en los diferentes lenguajes. Por lo tanto BSON proporciona a MongoDB dos capacidades: 1. Rápida escaneabilidad 2. Tipos de datos JSON proporciona únicamente 6 tipos de dato: • • • • • •
String Number booleans null arrays objetos objetos / documento documentoss
Los tipos de datos que maneja internamente BSON son los siguientes: ²http://json.org ³http://bsonspec.org
6
Introducción a MongoDB
• Double • String • Object • Array • Binary data • Undefined (Deprecated) • Object id • Boolean • Date • Null • Regular Expression • JavaScript Symbol JavaScript (with scope) • 32-bit integer • Timestamp • 64-bit integer • Min key • Max key Podemos ver BSON como un formato serializado de JSON.
Esquema BSON
La figura superior muestra el proceso de conversión JSON-BSON, en MongoDB los datos se almacenan en BSON y se envían en dicho formato, el encargado de realizar la conversión BSON<>JSON es el driver de Mongo de la plataforma cliente correspondiente.
Introducción a MongoDB
7
En el proceso de consulta de un documento el servidor de MongoDB nos sirve un BSON y nuestra APP a través del driver de Mongodb Mongodb transforma el BSON a JSON. Cuando enviamos información de nuestra APP al servidor enviamos un JSON y el driver es el encargado de convertirlo a BSON para su envío. Todo este proceso se realiza de forma transparente. Los nombres de los campos tienen las siguientes limitaciones: • El nombre de campo _id está reservado para la primary key; debe ser único e inmutable, y puede ser de cualquier tipo excepto array. array. • Los nombres no pueden empezar por el signo dólar ($). • Los nombres no pueden contener punto (.). • Los nombres no pueden contener el caracter null.
Instalación MongoDB está disponible para: - Windows - Mac - Linux En la documentación oficial de MongoDB se indica como instalar MongoDB en cada sistema operativo, a modo de resumen es de la siguiente forma:
Instalación en Windows Debemos descargarnos la versión correcta (64 o 32 bits) de la web oficial⁴ de oficial⁴ de MongoDB. La extensión del archivo descargado es “.msi” y haciendo doble click comenzará la instalación. Para configurar el entorno es necesario definir el directorio donde guardará MongoDB los datos. Por defecto es “c:\data\db”‘ “c:\data\db”‘ 1
md \ data\ data\ db
Es posible especificar otra ruta mediante el siguiente comando: 1
C:\mongodb\ mongodb\bin\ bin\mongod.exe -- dbpath "d:\test\mongodb\data"
Ahora debemos definir las variables de entorno en el sistema operativo: 1. Panel de control 2. Sistema 3. Configuración avanzada 4. Variables Variables de entorno 5. Bajo “Variables “Variables de sistema” busca “Path” “Path” y haz doble click en el. el. 6. En el valor “Variable” “Variable” de esa fila seleccionada seleccionada debemos añadir al final ; si no existe y añadir añadir la ruta de instalacion de MongoDb: Por ejemplo yo he añadido al final: 1
;C: ;C:\mongodb\ mongodb\bin
Instalación en MAC Existen dos formas de instalar en OSX MongoDB: - Instalar en OSX con Homebrew - Instalar en OSX manualmente
Instalar en OSX con Homebrew ⁴http://www.mongodb.org/downloads
9
Instalación 1
brew update update
2
brew install install mongodb mongodb
Instalar en OSX manualmente Debemos descargarnos los binarios desde web desde web oficial⁵ . oficial⁵ . mongodb-osx-x86_ -x86_64-3. 64-3.0.2.tg 0.2.tgz z Copiamos Descomprimimos el paquete descargado: tar -zxvf mongodb-osx mkdir -p mongod mongodb b la carpeta descomprimida a la localización desde la que lanzaremos MongoDB: mkdir archivos binarios binarios de MongoDB se encuenencuencp -R -n mongodb-osx mongodb-osx-x86_ -x86_64-3.0 64-3.0.2/ .2/ mongodb mongodb Los archivos tran en el directorio bin/ Para agregar los binarios al PATH: export PATH=
con con la ruta de nuestra carpeta de de directory>/bin:$PATH Reemplazar Mongodb recientemente descomprimida y copiada.
Instalación en Linux Debemos descargarnos los binarios desde web desde web oficial⁶ . oficial⁶ . Descomprimimos el paquete descargado:
tar -zxvf mongodb-linu mongodb-linux-x86 x-x86_64-3. _64-3.0.2.t 0.2.tgz gz
Copiamos la carpeta descomprimida a la localización desde la que lanzaremos MongoDB:
mkdir
-p mongod mongodb b cp -R -n mongod mongodb-l b-linu inux-x x-x86_ 86_6464-3.0 3.0.2/ .2/ mongod mongodb b
Los archivos binarios de MongoDB se encuentran en el directorio bin/ Para agregar los binarios al PATH: export PATH=/bin:$PATH Reemplazar con la ruta de nuestra carpeta de Mongodb recientemente descomprimida y copiada. Antes de iniciar mongod creamos la carpeta donde se encontrarán las bases de datos: /data/db
⁵http://www.mongodb.org/downloads ⁶http://www.mongodb.org/downloads
mkdir mkdir -p
Mongo Shell En la carpeta donde tenemos instalado MongoDB hay una carpeta “bin”, en ella encontraremos todos los ejecutables de MongoDB. Los más usados son: • mongod: es el demonio de base de datos, datos, debemos ejecutarlo y dejarlo en ejecución ejecución para poder lanzar consultas y trabajar. trabajar. • mongo: es el shell desde el cual lanzaremos las consultas. • mongos: es un servicio de routing de MongoDB Shard. Por lo que si no tienes ya iniciado mongod lo primero es iniciarlo con:
mongod
Ahora vamos a empezar a lanzar consultas contra nuestro mongod, para ello accedemos a nuestro shell escribiendo: mongo Por defecto intentaremos conectarnos al mongod de localhost en el puerto 27017. Si deseamos conectarnos a otro demonio de MongoDB debemos especificar el puerto y el host mediante: –port y –host. Mongo shell es parte de MongoDB y proporciona un entorno completo de Javascript además de una interfaz para MongoDB. Desde el shell estos son los comandos más básicos y utilizados, no hace falta que los probeis, de momento esta lista es para que os vayan sonando ya que los iremos utilizando a lo largo del libro: Mostrar la base de datos actual:
db
Muestra la lista de bases de datos:
show dbs
Seleccionaremos la base de datos “midb”: use
midb midb
Si realizamos una búsqueda en una colección de la base de datos elegida:
db.usuarios.find()
El shell de MongoDB devolverá un cursor con los primeros 20 resultados, si queremos mostrar más usaremos la palabra “it” para iterar el cursor. Un cursor se cerrará pasados 10 minutos o cuando iteramos todos sus resultados. Podemos modificar el tiempo que permanecerá abierto el cursor. Podemos establecer el tiempo máximo del cursor con el siguiente comando: var micursor micursor = db.usuario db.usuarios.find s.find() () micursor.ma micursor.maxTimeM xTimeMS(120 S(1200000) 0000) El comando anterior ampliará el tiempo máximo de “micursor” a 20 mininutos (el parametro que recibe es milisegundos, 1200000==20min), aunque si es iterado completamente se cerrará antes de ese tiempo máximo. Para imprimir un documento JSON de forma más “bonita” tenemos las siguientes opciones:
Mongo Shell
11
• .pretty() Al final de una consulta • printjson() == print(tojson()) Para imprimir variables. db.usuarios.find s.find() () Para obSi queremos almacenar un array en una variable: var users = db.usuario tener el indice 4 o la posición 4 del cursor almacenado en la variable users creada en la linea printj tjso son( n( users users [ 4 ] ) Mongo "_id" : anterior: prin Mongo devolverá devolverá el usuario usuario en esa posición: posición: { "_id" ObjectId("51a7dc7b2cacf40b79990bea"), "nombre" : "Joseba", "surname" : "Madrigal" }
Cuando accedes a un cursor por un índice, internamente mongo llama a “cursor.toArray()” para convertir el cursor en un array donde poder manejar índices y almacena TODOS los documentos que devuelve el cursor en la memoria RAM. Para resultados muy grandes de documentos es posible que mongo devuelva: “out of available memory” ya que no cabe todo en la RAM.
CRUD Las operaciones CRUD (Create, Read, Update, Delete) existen en Mongodb en forma de funciones. No se puede usar SQL, se utilizan las funciones o métodos que nos proporciona MongoDB. • C(create) -> insert, save, update(upsert) • R(read) R(read) -> find, find, findOne findOne • U(update) -> update, save • D(delete) -> remove
Insert 1 db.collection.insert( 2
< document or array array
3
{
documents>, of documents>
4
writeConcern: writeConcern: < document document> >,
5
ordered: ordered:
6 7
} )
Para insertar un documento en MongoDb utilizaremos la función insert sobre la colección de una base de datos. Si la colección no existe, la creará automáticamente. Por ejemplo: 1
var
doc = {"name" "name": : "Joseba", "Joseba", "surname": "surname": "Madrigal", "Madrigal", "website": "website": "http://josebamad\
2 rigal.com"}; rigal.com"}; 3
db.people.in db.people.insert( sert( doc );
• Primero generamos una variable doc e introducimos un objeto en formato JSON. • db.people representa representa la colección de datos donde insertaremos insertaremos el documento. Puede no existir, existir, en caso de que no exista se creará automáticamente. • No hemos añadido parámetros writeConcern ni ordered en esta ocasión, los comentaremos más adelante ya que esta es nuestra primera inserción en MongoDB. ¡Felicidades, ya has insertado tu primer documento en la base de datos! Si hacemos una búsqueda de todos los documentos que hay en la colección people:
13
CRUD 1 db.people.find();
Observaremos que además de nuestras claves y valores MongoDB ha insertado automáticamente una clave clave “_id” “_id” conun con un Object Object ID con una estruc estructur turaa simila similarr a: Object ObjectID(“ ID(“507 507f19 f191e8 1e810c 10c197 19729d 29de86 e860ea 0ea”). ”). Eso ocurre porque automáticamente MongoDB añadirá a nuestros documentos una clave primaria única e inmutable (no se puede cambiar una vez insertada) llamada _id. El _id por lo tanto será único dentro de cada colección de documentos, además será inmutable por lo que podríamos localizar inequívocamente un documento dentro de una colección por su _id. La única forma de “cambiar” un _id a un documento es borrándolo y volviéndolo a insertar, el _id generado automáticamente será diferente. Si deseamos crear nuestra propia clave única podemos insertar nosotros un _id por ejemplo: 1
var
doc = {"\_id" "\_id": : "[email protected]", "[email protected]", "name": "name": "Joseba", "Joseba", "surname": "surname": "Madrigal"}; "Madrigal"};
2
db.people.in db.people.insert( sert( doc );
El _id de este documento será “[email protected]”. He elegido una cuenta de correo ya que es una clave primaria única e inmutable para la mayoría de aplicaciones ,(es muy raro que se cambie el email), normalmente se suele utilizar como nombre de usuario para el login. Podríamos utilizar el dni perfectamente ya que identifica este tipo de documento, pero debes ser cuidadoso al elegir la clave, si no crees que puedas hacerlo deja que MongoDb genere automáticamente el _id por ti.
update 1 db.collection.update( 2
{ query>},
3
{ update>},
4
{
5
upsert: upsert: ,
6
multi: multi: ,
7
writeConcern: writeConcern: < document document> >
8 9
} )
• upsert: true -> Hace que si el documento no existe se cree y si existe lo actualiza. Si lo establecemos a false ,si existe lo actualiza, en caso contrario no hace nada. • multi: multi: true -> Especifica Especificamos mos que queremos queremos actualizar actualizar múltiples múltiples documento documentos, s, por defecto es false de modo que solo se actualiza actualiza un único documento documento,, esto es importante importante ya que en SQL un update actualiza todas las coincidencias, en MongoDB por defecto multi es false por lo que solo actualizará la primera coincidencia.
CRUD
14
• writeConcer -> Hablaremos de este concepto concepto en el tema de “ReplicaSet”, “ReplicaSet”, se trata de una opción para definir en cuantas réplicas de servidores mongo debe estar escrito el cambio para devolver un “OK”. Existen dos formas de update en Mongodb. - Update de “reemplazo de documento completo” Update “parcial” Podemos actualizar un documento completo, para ello especificaremos en el primer parámetro la query con el documento que queremos actualizar, en el segundo la actualización que queremos aplicar y en el tercer parámetro las opciones. Por ejemplo: 1
db.people.up db.people.update( date( { name: name: "Joseba" }, { name name: : "Jose", "Jose", active active: : 1 }, { upse upsert rt: : tru\ tru\
2
e } )
Con el update anterior vamos a editar el documento completo con “name” “Joseba” y vamos a introducir el nombre “Jose” y active con valor 1. Realiz Realizand andoo esta esta update update perder perderemo emoss los campos campos que no hayamo hayamoss especi especific ficado ado,, quedar quedaraa un docume documento nto tal y como hemos especificado: Para editar uno o varios campos y preservar el documento o lo que es lo mismo realizar un “update parcial” debemos utilizar el operador $set, por ejemplo: 1
db.people.up db.people.update( date( { name: name: "Joseba" }, { $set $set: : {name: {name: "Jose", "Jose", fullstack fullstack: : 1 } } , {\ {\
2 upsert: upsert: true } )
De esta forma realizaremos un update parcial y añadiremos fullstack: 1 , cambiaremos el nombre por “Jose” y mantendremos intactos los campos que existiesen previamente. Si no agregamos la opción multi:true solo se modificará 1 documento, si lo añadimos se modificarán todos los usuarios que tengan el nombre “Joseba”.
save .save realiza la misma acción que update con “upsert” por defecto. Es decir, si no exist el _id insertará el nuevo documento y si existe lo actualizará.
15
CRUD 1 db.collection.save( 2
< document document> >,
3
{
4
5 6
writeConcern: writeConcern: < document document> > }
)
Por ejemplo: 1
db.people.sa db.people.save( ve( { _id: _id: ObjectId("50691737d386d8fadbd6b01d" ObjectId("50691737d386d8fadbd6b01d"), ), nombre nombre: : "Patxi", "Patxi", su\ su\
2 rname: rname: "Etxeberria" } )
Si el id existe actualizará el documento, si no existe lo creará.
find y findOne find({WHERE},{PROJECTION}) Para buscar los documentos que insertemos en la base de datos podemos utilizar find() o findOne(). La diferencia es que find retorna un cursor con todos los documentos coincidentes y findOne solo un documento, si existiese más de una coincidencia será uno al azar. Si lanzamos find() sin argumentos: 1 db.people.find()
Obtendremos todos los documentos de la colección. Por el contrario si ejecutamos sin argumentos findOne() : 1 db.people.findOne()
Obtendremos un documento al azar. azar. En la sección sección anterior anterior “MongoDB “MongoDB Shell” ya hemos comentado comentado algo sobre sobre los cursores, cursores, si no estás familiarizado aún con las consultas y los cursores ahora si que te recomiendo volver atrás y practicar algunas consultas para familiarizarte con MongoDB. Podemos utilizar argumentos en find() o findOne() para buscar por una clave concreta, por ejemplo: 1 db.people.findOne({"\_id" db.people.findOne({"\_id": : "[email protected]"}) "[email protected]"})
En este caso retornará nuestro registro y estamos seguros que no hay más ya que hemos buscado sobre la clave primaria y única.
16
CRUD 1
{"\_id" "\_id": : "[email protected]", "[email protected]", "name": "name": "Joseba", "Joseba", "surname": "surname": "Madrigal"} "Madrigal"}
Si querem queremos os buscar buscartod todos os los usuari usuarios os quese que se llaman llaman “Joseb “Joseba” a” dentro dentrode de la colecc colección ión:: db.peo db.people ple.fi .find( nd({“n {“name ame”: ”: “Joseba”}) Retorna todos los usuarios llamados “Joseba”. Si especificam especificamos os un segundo segundo parámetro parámetrodefin definirem iremos os los campos campos que queremos queremos recibir: recibir: db.people db.people.find( .find({“name {“name”: ”: “Joseba”}, {“surname”: true, _id:false}) Devuelve los apellidos de las personas que se llaman Joseba: {“surname”: “Madrigal”}
remove 1
db.collection.remove(query, {justOne: {justOne: boolean, writeConcer writeConcern n: document}) document})
Es un borrado de múltiples documentos por defecto a no ser que se especifique justOne a true.
findAndModify Modifica y retorna un único documento. 1 findAndModify: findAndModify: name>, 2
query: query: < document document> >,
3
sort: sort: < document document> >,
4
remove: remove: ,
5
update: update: < document document> >,
6
new:
,
7
fields: fields: < document document> >,
8
upsert: upsert:
Operadores Podemos utilizar los siguientes operadores para evaluar en nuestras consultas. • $eq -> (Equal) Evalúa si un campo es igual al valor que se le pasa. • $gt -> (Greater than) Evalúa si un campo es mayor que el valor pasado. • $gte -> (Greater than or equal) Evalúa si un campo es mayor o igual que el valor pasado. • $lt -> (Lesser than or equal) Evalúa si un campo es menor que el valor pasado. • $lte -> (Lesser than or equal) Evalúa si un campo es menor o igual que el valor pasado. • $ne -> (Not equal) Evalúa si un campo no es igual al valor. • $or -> (O) (O) • $and -> (Y) • $exists -> {exists: true} evalúa si existe(no es nulo). • $in -> Evalúa si el valor se encuentra dentro del array. • $nin -> (Not in) Evalúa si el valor no se encuentra dentro del array. • $all -> Evalúa si todos los valores se encuentran dentro del array. • $mod -> (Modulo) Aplica la operación de módulo y lo compara con el valor pasado. • $regex -> Selecciona los documentos que casan con el valor de la expresión regular. • $text -> Realiza una busqueda de texto. • $where -> Casa con los documentos que satisfagan una expresión en JavaScript. Por ejemplo si queremos buscar los usuarios de 18 años:
db.p db.peo eopl ple. e.fi find nd({ ({ age : { $eq $eq : 18 }
} )
Por ejemplo si queremos buscar los usuarios mayores de 18 años y menores de 50 o de 50 en nuestra colección “people”: 1
db.people.fi db.people.find({ nd({ age : { $gt $gt : 18 , $lte $lte : 50 } } )
Si quer querem emos os busc buscar ar los los docu docume ment ntos os con con una una cant cantid idad ad meno menorr que que 20 o un prec precio io de 10 10:: db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } )
18
Operadores
Operadores especiales: Geoespaciales • $geoWithin: Selecciona geometrías dentro de una geometría GeoJSON. Los índices 2dsphere y 2d soportan $geoWithin. $geoWithin. • $geoIntersects: Seleccionan las geometrías con intersección en un GeoJSON. Los índices 2dsphere y 2d lo soportan. • $geoIntersects. • $near: Devuelve un objeto geoespacial en la proximidad de un punto. Require un índice geoespacial. Los índices 2dsphere y 2d soportan $near. • $nearSphere: Devuelve un objeto geoespacial en la proximidad de un punto de la esfera. Require un índice geoespacial. Los índices 2dsphere y 2d soportan $nearSphere.
Array Para los campos que contienen Arrays, MongoDB proporciona los siguientes operadores: • • • •
$elemMatch $slice $. $size
Por ejemplo, the inventory collection contains the following document:
{ "\_i "\_id" d" : 1, "name "name" " :
"Jos "Joseb eba" a", , "lan "langu guag ages es" " : [ "JS" "JS", , "PHP "PHP", ", "HTM "HTML" L" ] }
Si quisiéramos obtener solo los dos primeros elementos del array languages lo haríamos de la db.inv nven ento tory ry.f .fin ind( d( { \_id \_id: : 1 }, { lang langua uage ges: s: { $sli $slice ce: : 2 } } ) siguiente manera: db.i
Modelado de datos Si vienes del mundo sql estarás acostumbrado a crear entidades, aplicar las formas normales… En MongoDb se crean los esquemas de la base de datos orientados al uso que se le da a los datos en la aplicación. Este tipo de diseño de esquema se llama “Application driven schema”. Analizaremos los datos y los patrones de acceso que se usarán en el programa para crear un esquema a esos datos. Muchas veces nos encontraremos con la duda de si embeber un documento o no. Por ejemplo en un blog, imaginemos una colección post: 1
{
2
"author"
: "Joseba", "Joseba",
3
"title"
: "Mongodb introd introductio uction" n", ,
4
"text"
: "Mong "MongoDB oDB is a nono-sql sql doc docume ument nt ori orient ented ed dat data a bas base e ... ..." ",
5
"comments" : [
6
{"author" "author": : "Patxi", "Patxi", "comment": "comment": "Thank "Thanks s for thi this s pos post!" t!" },
7
{"author" "author": : "Juan", "Juan", "comment": "comment": "Nice post! post!" " }
8 9 10
],
"tags"
: ["javascript" "javascript", , "mongodb", "mongodb", "jquery", "jquery", "angularjs"], "angularjs"],
}
Normalmente si no vamos a acceder de forma independiente al contenido de un comentario y sabemos que no seran muchos los comentarios o seran limitados, lo embeberemos. Lo normal es que al mostrar el post mostremos abajo los comentarios, es difícil querer leer un comentario sin ver el post del que se trata, MongoDB está orientado a la programación. Cuando tengas duda entre embeber o no, decántate por la forma en la que vas a acceder a los datos. Reglas: - Relaciones 1-1: Por ejemplo un usuario tiene un único dni y ese dni no pertenece a nadie más que a ese usuario. Ese tipo de datos deben estar siempre embebidos en un docunick: "joseb "josebyte yte", ", pass: pass: "1234" "1234", , type: type: "admin "admin", ", dni:{ dni:{ codicodimento dentro del usuario: usuario: { nick: go: "78964914f", fechaEmision: "", fechaCaducidad: "", padre: "", madre: "" } } -Relaciones 1-n: Por ejemplo un usuario tiene de 0 a n coches y cada coche pertenece únicamente a un usuario. Ese tipo de datos se deben embeber en un array de documentos:
Modelado de datos 1
{
2
nick: nick: "josebyte", "josebyte",
3
pass: pass: "1234", "1234",
4
type: type: "admin", "admin",
5
cars: cars:[
6
{marca: {marca: "Ford", "Ford", año: año: "2009", "2009", matricula matricula: :"1234-GGG" "1234-GGG"}, },
7
{marca: {marca: "Opel", "Opel", año: año: "2001", "2001", matricula matricula: :"4321-JJJ" "4321-JJJ"} }
8 9
20
] }
• Relaciones n-m: Si pensamos en el el ejemplo anterior y que un coche puede puede tener varios usuarios usuarios el ejemplo anterior sería n-m y en lugar de embeber los datos en el documento deberiamos crear otra coleccion:
1
Colección Colección usuarios usuarios: :
2
{
3
nick: nick: "josebyte", "josebyte",
4
pass: pass: "1234", "1234",
5
type: type: "admin", "admin",
6
cars: cars:[
7
11154, 11154,
8
11155
9 10
] }
11 12
Colección Colección coches coches:
13
{"_id" "_id": : 11 1115 154 4, "marca": "marca": "Ford", "Ford", "año": "año": "2009", "2009", "matricula": "matricula":"1234-GGG" "1234-GGG"} }
14
{"_id" "_id": : 11 1115 155 5, "marca": "marca": "Opel", "Opel", "año": "año": "2001", "2001", "matricula": "matricula":"4321-JJJ" "4321-JJJ"} }
Nota: Se podra embeber en usuarios el array de coche o a la inversa, un array conductores dentro de los documentos coches que contendrá el _id de cada usuario de ese coche. Dependerá de cómo se va a acceder a los datos en el programa. Embeber documentos 1-1 y 1-n proporcionará mayor rapidez de lectura. Es importante que se analicen las lecturas y escrituras que realizará el programa sobre la base de datos para orientar el modelo de base de datos y mejorar la eficiencia.
Índices Introducción Los índices en MongoDB funcionan igual que en cualquier base de datos. Si realizamos una consulta en una base de datos sin usar índices la consulta será lenta debido a que se recorrerán todos los documentos de la colección para comprobar si se cumple la consulta. Sin embargo si disponemos de un índice, los elementos están ordenados y como sabréis no es lo mismo buscar palabras en un diccionario que en una sopa de letras… el diccionario lleva un índice alfabético en las palabras.
Consideraciones Cuando creas índices debes tener en cuanta lo siguiente: • Por defecto los _id de todas las colecciones tienen un índice. • Cada índice requiere 8KB de espacio. • Añadir un índice tiene un impacto impacto negativo para las operaciones de escritura. escritura. Para colecciones con alto ratio escritura>lectura, los índices son caros ya que cada inserción también debe actualizar los índices. • Las colecciones con alto ratio lectura>escritura lectura>escritura a menudo menudo se benefician de índices adicionales. adicionales. Los índices no afectan al rendimiento de las lecturas que no usen índices. • Cada índice activo activo consume espacio en disco y memoria. Este uso puede ser importante y debe ser analizado para la planificación de la capacidad.
Ver indices Puedes ver todos los índices de la base de datos con la siguiente consulta: 1 db.system.indexes.find()
Si quieres ver los indices de una colección concreta:
db.micoleccion.getIndexes()
Si quisiéramos ver el tamaño de los índices de una colección: db.micoleccion.totalIndexSize()
22
Índices
Funcionamiento de los índices Si creamos un índice para “nombre”: db.createIndex({nombre:1}) - Las consultas sobre sobre nombre usaran el índice. Si creamos un índice sobre “nombre” y “apellido”. db.createIndex({nombre:1, apellido:1}) * Las consultas sobre “nombre” usarán el índice. * Las consultas sobre “nombre” y “apellido” usarán el índice. * Las consultas sobre s obre “apellido” NO usarán el índice. * Las consultas sobre “nombre” y “edad” usarán el índice pero solo la parte de “nombre”. Puedes forzar usar un índice determinado indicando a la consulta .hint({campo:1}) .hint({$natural:1}) //para no usar indice Por defecto en el log encontraremos las consultas que tardan mas de 100ms Podemos usar profiler para establecer el nivel de capturas que deseamos realizar: * 0 desactivado * 1 consultas lentas * 2 todas las consultas 1 db.setProfilingLevel(2 db.setProfilingLevel(2)
1 db.system.profile.find()
Crear indices Para Para crear crear un índice índice:: db.micoleccion.createIndex({micampo:1})
db.micoleccion.ensureIndex({micampo:1})
//Para //Para versio versiones nes previa previas s a 3.0
Podemos crear índices compuestos de varios campos
db.micoleccion.createIndex({{micampo:1
, orden:1}) orden:1})
Índice unico 1 db.micoleccion.createIndex({{micampo:1 db.micoleccion.createIndex({{micampo:1},{unique },{unique: :true})
o
Eliminar duplucados Si en la creación indicamos la opción dropDups:1 eliminaremos los valores duplicados.
Borrar indece:
23
Índices 1 db.micoleccion.dropIndex({micampo:1 db.micoleccion.dropIndex({micampo:1}); });
Multikey index Si creamos un índice de un campo que es un array será un índice multikey. No puedes crear un índice compuesto sobre dos campos multikey, en ese caso debes crear dos índices separados. Si existe un documento con valores y creas un índice ya se considera multikey pese a que el resto de valores sean numéricos o string. Si hacemos un .explain() de una consulta y dice isMultiKey significa que usa es un índice multikey.
Sparse index Los índices creados con la opción sparse:1 generará índices solo para los campos con valor disntito de null. Es usado principalmente en conjunto con unique ya que si no disponen ese campo se considera que tienen null y hay valores duplicados.
Índices en background Por defecto se lanzan en foreground y son mas rápidas pero bloquean las escrituras en la misma base de datos. En background no bloqueará las escrituras pero será bastante más lento. Una instancia de mongod solo puede construir un índice en background por base de datos. Una creación de índices en background permite escrituras pero bloquea el shell.
Indices geoespaciales Hay dos tipos de indices geoespaciales: * 2D [x,y] * 2D Sphere [long, lat] 2d
createIndex createIndex({loca ({location: tion: "2d", type: 1}) find({ location:{$ location:{$near:[ near:[x,y]} x,y]} }).limit(30 }).limit(30) )
spherical
create createInd Index( ex({lo {locat cation ion: : "2dsph "2dsphere ere", ", type: type: 1}) find({ find({ locati location: on:{ { $near: $near: { $geo$geo-
metry: metry:{ { type: type: "Point "Point", ", coordi coordinat nates: es: [lat, [lat, long] long] } $maxDi $maxDista stance nce: : 2000 2000 } } }).lim }).limit( it(30) 30)
Full text search
Índices
24
1 createIndex({mitexto: createIndex({mitexto: "text"}) "text"}) 2 find({$text: find({$text:{$search: {$search:{"dog" "dog"}}}) }}}) 3 find({$text: find({$text:{$search: {$search:{"do "dog g CAT CAT" "}}})
Hace un OR con las palabras. Podemos proyectar y ordenar por $meta:”textScore” para obtener los mejores resultados para nuestra busqueda ordenados
mongotop Muestra tiempos de lectura, escritura y totales por cada colección. Podemos lanzarlo con: 5milisegundos 5 Refrescará cada 5milisegundos
mongostat Muestra update, query delete por query. Nos dice si el índice está en memoria o no.
mongotop
Agregation MongoDB dispone de herramientas para hacer consultas sobre agrupaciones de documentos. Podemos agrupar datos de varios documentos y realizar operaciones sobre esa agrupación. Utilizaremos agregaciones por ejemplo para mostrar estadísticas sobre nuestros documentos. Funciona de forma similar al comando GROUP BY y HAVING de SQL. Si quisiésemos agrupar y contar cuantos usuarios hay por país: 1 db.usuarios.aggregate([ 2
{
3 $group: $group: { 4
"_id": "$pais", "_id": "$pais",
5
"num_usuarios": {$sum: "num_usuarios": {$sum: 1}
6
}
7
}
8
])
Si quisiésemos agrupar por usuarios de cada país y provincia:
db.usuarios.aggregate([ {
$group: $group: { "_id": "_id": { "pais":"$pa "pais":"$pais", is", "provincia": "provincia":"$pro "$provincia vincia" " }, "num_usuari "num_usuarios": os": {$sum:
- El prim primer er pará paráme metr troo de cada cada id entr entrec ecom omil illa lado do que que no tien tienee $ es el nomb nombre re que que noso nosotr tros os queramos mostrar. - El valor con $ después de “pais” y “provincia” debe coincidir con el campo de la base de datos. - $sum es una expresión que suma 1 por cada documento.
1} } } ])
La agregación usa un pipeline, y cada una de estas fases pueden aparecer más de una vez en el pipeline: • $project -> remodela el documento seleccionando los campos deseados o trayéndolos de lo más profundo a lo más alto. 1-1 • $match $match -> filtra. filtra. n-1 • $group -> puedes sumar contar y agrupar por determinado campo. n-1. • $sort -> -> ordenació ordenación. n. 1-1 • $skip -> saltar documentos. n-1 • $limit -> limitar los resultados. • $unwind -> normaliza el array, array, por ejemplo: tags:[“rojo”, tags:[“rojo”, “azul”] se convertirá en: tags: “rojo”, “rojo”, tags: “azul” • $out -> redirigir la salida a otra coleccion en lugar de a un cursor (por defecto) 1-1 Expresiones:
26
Agregation
• $sum • $avg • $min • $max • $push • $push • $addToSet • $first -> requiere que ordenes con sort los documentos • $last -> requiere que ordenes con sort los documentos Si quis quisié iéra ramo moss suma sumarr los los punt puntos os de cada cada pais pais que que han han obte obteni nido do los los usua usuari rios os:: db.usuarios.aggregate([ { $group $group: : { "_id": "_id": "$pais "$pais", ", "punto "puntosPo sPorPa rPais" is": : {$sum: {$sum: "$punt "$puntos" os"} } } } ])
Si quisiéramos calcular la media de puntos de cada país:
db.usuarios. db.usuarios.aggre aggregate([ gate([ { $group: $group: {
"_id": "_id": "$pais "$pais", ", "media "mediaDeP DePunt untos" os": : {$avg: {$avg: "$punt "$puntos" os"} } } } ])
Si quisiéramos mostrar las provincias que tienen usuarios:
db.usuarios db.usuarios.aggr .aggregate( egate([ [ { $group: $group:
{ "_id": "_id": "$pais "$pais", ", "provi "provinci ncias" as": : {$addT {$addToSe oSet: t: "$prov "$provinc incia" ia"} } } } ]) db.usuarios.aggrega ggregate([ te([ Si quisié quisiéram ramos os obtene obtenerr el mejor mejor usuari usuarioo de cada cada país: país: db.usuarios.a id": id": "$pais "$pais", ", "maxPu "maxPunto ntos": s": {$max: {$max: "$punt "$puntos" os"} } } } ])
{ $group: $group: { "_-
ReplicaSet La forma de lograr alta disponibilidad y y tolerancia a fallos es es con las replicaSet . Con sharding lo que se hace es partir la información en varios fragmentos por lo que lo que logramos es escalabilidad. Para crear un sistema con tolerancia a fallos y alta disponibilidad debemos crear un ReplicaSet. Vamos a plantear un esquema comun de 3 nodos de mongod (el mínimo de nodos es 3 para un ReplicaSet) funcionando con los mismos datos y trabajando en equipo. Hay tres tipos de nodo en los ReplicaSet: • Normal (Primario y Secundarios) • Delayed o “con retraso” • Arbitro • Oculto Los datos se escriben sobre el primario y luego se replican asincronamente en los secundarios. Los árbitros nunca pueden convertirse en primarios y unicamente entran en accion cuando el nodo primario se cae y es necesario votar para elegir un nuevo primario. Para tener un nuevo primario debes tener una mayoría estricta del numero original de nodos. Cuando un nodo se recupera vuelve como secundario. Las elecciones de nodo primario se realizan de forma transparente para el usuario. Veamos como hacer un replicaSet para lograr alta disponibilidad y tolerancia a fallo. Antes de nada debo decir que lo lógico y natural es que para lograr lo anterior debemos disponer de 3 servidores distintos ya que si los montamos sobre la misma maquina no estamos solucionando nada en el caso de que se caiga o se rompa. Aclarado eso y solo con fines educativos crearemos el replicaset sobre la misma maquina en diferentes puertos (ya sabemos que esta mal pero es solo para aprender). Lo primero vamos a especificar un nombre para nuestro replicaSet mediante: 1 mongod ---replSet replSet "rs0"
Este comando creará un replicaSet con el nombre “rs0”. Ahora accedemos al shell de mongo: mongo E iniciamos el replicaSet:
rs.initiate()
Mediante el siguiente comando podremos ver la configuración del replicaset:
rs.conf()
28
ReplicaSet
Podemos guardarlo y editar esa información añadiendo dos miembros más tal y como puede apreciarse aquí: { "_id "_id" " : "rs0 "rs0", ", "ver "versi sion on" " : 1, "memb "member ers" s" : [ { "_id "_id" " : 1, "host "host" " : "loc "local alho host st:2 :270 7017 17" " }, { "_id "_id" " : 2, "hos "host" t" : "loc "local alho host st:2 :270 7018 18" " }, { "_id "_id" " : 3, "hos "host" t" : "local "localhos host:2 t:2701 7019" 9" }, ] }
O tambié tambiénn podemo podemoss añadir añadirlos los porcom por comand ando: o: rs.add("mongodb1.example.net") Finalmente podemos comprobar el estado de nuestra replicaSet de esta forma:
rs.add("mongodb2.example.net
rs.status()
Sharding La forma de lograr alta disponibilidad y tolerancia a fallos es con las replicaSet. Con sharding lo lo que se hace es partir la información en varios fragmentos por lo que lo que logramos es escalabilidad horizontal. Median Mediante te el shardi sharding ng divid dividimo imoss nuestr nuestros os datos datos almace almacenad nados os en Replic Replica-S a-Sets ets en difer diferent entes es servid servidor ores. es. El número mínimo de shards en producción es de 3. Las particiones de información se realizan basadas en rangos sobre la shard-key la shard-key.. La shard-key consiste en un campo inmutable que exista en todos los documentos de nuestra colección. El sharding sirve para repartirse uniformemente la carga de trabajo de la base de datos, permitiendo escalar y manejar grandes cantidades de datos. • Escalabilidad: Permite particionar, de manera transparente para el usuario, nuestra base de datos en shards. Esto aumenta el rendimiento al ser cada una de ellas más pequeña que la original. • Auto balanc balancead eadoo de carga carga a travé travéss de los disti distinto ntoss shards shards.. El balanc balancead eador or decide decidecuá cuándo ndo migrar migrar los datos, y a qué Shard, para que estén uniformemente distribuidos entre todos los servidores del cluster. Imaginemos disponemos de una coleccion “pedidos” con gran cantidad de información almacenada. Disponemos de varias bases de datos y queremos repartir la información de esa coleccion “pedidos”. Para ello vamos a crear shards. S1, S2, S3, S4… Cada shard contine normalmente un replicaSet. Y para gestionarlos y enrutarlos se usa “mongos”. Mongos mantendra una especie de pool de conexiones de todos los hosts. En sharding se realiza una particion de datos por rango para almacenar los datos en funcion de su shard-key. Las particiones se realizan basadas en rangos sobre la shard-key. El shard-key es una clave que define el usuario para dividir los documentos en distintos servidores. Cuando establecemos un shard-key mongo dividira los valores en chunks. Esos “chunks” no dejan de ser una agrupación de datos en funcion de un campo dado. Cuando hacemos una consulta, mongod se comunica con mongos y si existe un shard que satisfaga la consulta, mira los chunks y ve donde tiene que enrutar enrutar la consulta. consulta. Por ejemplo si definimos definimos el shard-key con pedido_id y buscamos pedido_id=100. nuestro mongos podria enrutarnos al shard s2 que contiene ese documento despues de mapear los chunks.
30
Sharding
Como elegir una shard-key correctamente • Debes asegurarte que haya suficiente cardinalidad: Suficiente variedad de valores. Seria absurdo crear una shard-key sobre un campo en el cual los valores son casi todos iguales. • Evitar hotspots: Evitar asignar asignar la shard-key a campos que son monotonamente monotonamente crecientes. Los chunks tiene un minkey y un maxkey. Los campos como _id que solo crecen iran siempre al shard mas alto y no lograremos lo que estamos buscando. Supong Supongamo amoss que estamo estamoss buscan buscando do la shardshard-ke keyy para para una colecc coleccion ion de pedido pedidoss con order order_id _id,, order_ order_-date y vendor. ¿Cual es el shard-key ideal para esta coleccion? Si deseamos seguir los consejos anteriores deberiamos descartar order_id order_id ya que crecera monotonamente. ¿Entre order_date y vendor cual es mejor shard-key? Si vendor tiene suficiente s uficiente cardinalidad podria ser una buena elección. El order_date tiene un problema y es que normalmente se ira incrementando y podriamos tener hotspot asi que no es una gran eleccion. Vendor podria funcionar bien como shard-key.
Configurar shard-key Esta labor quiza este mas orientada para los DBA pero a continuación detallo como se realizaria una configuracion de shards. Creamos la carpeta donde almacenaremos la base de datos. Iniciamos la configuración:
mkdir /data/confi /data/configdb gdb
mongod mongod --configsvr --configsvr --port 27000 --dbpath /data/configdb /data/configdb
Por ejemplo si disponemos de los siguientes hosts: cfg0.mishard.net cfg1.mishard.net cfg2.mishard.net Escribire Escribiremos mos lo siguiente siguientepara para configura configurarlo: rlo: mongos
--configdb cfg0.mishard.net:27019,cfg1.mishard.net:2
Nota: Cada “mongos” shard debe usar la misma configDB string con los mismos nombres de host en el mismo orden.
Añadir un shard al cluster Para añadir un shard al replicaSet llamado rs1 con un miembro corriendo en mongodb0.example.net: mongodb0.example.net: sh.addShard( "rs1/mongodb0.example.net:27017" )
Notas:
Sharding
31
• En entornos de producción se debe ejecutar cada una de las instancias de servidor en un servidor distinto para garantizar una respuesta rápida y seguridad. Con fines de testing es posible configurar cada shard en el mismo servidor. • Es importante que todas las instancias de servidor tengan acceso al resto de instancias por lo que la configuracion del firewall y la red debe realizarse correctamente. • Por defecto cada servidor almacena la información en: /data/configdb • Por defecto mongos se ejecuta en el puerto 27017.
Bibliografía El material que me ha ayudado a escribir este libro y considero de tu interés es el siguiente: Documentación oficial de MongoDB: https://docs.mongodb.org/manual/ https://docs.mongodb.org/manual/ Cursos gratuitos de Mongo University: M101