Publica tu how-to

Dinos como hacer lo que sabes hacer, mándanos un email a wdonet@gmail.com y lo publicamos (dos días máximo) o si te interesa unirte al equipo de redactores, también háznoslo saber por correo.

Introducción a MongoDB


Me metí un poco a ver como funcionaba CouchDB pero entre revisiones y vistas rápidas a referencias aquí y allá llegue a MongoDB, ambas son alternativas No-SQL (termino que empezó a agarrar fama desde 2009) y que su almacenamiento de datos está orientado a documentos JSON y BSON (Bynary JSON) para ofrecer sistemas flexibles, rápidos, ligeros, potentes y fáciles de usar.

Según Eliot Horowitz, 10gen CTO y co-fundador de mongoDB, prácticamente podrías tomar una base de datos hecha en MySQL, cambias el modelo relacional a uno basado en documentos y obtendrías varias mejoras como:
  1. Documentos embebidos para mejorar la velocidad
    1. El uso de json es más amigables con objetos en lenguajes de programación
    2. El meter documentos embebidos y arreglos reduce la necesidad de hacer joins
  2. Manejabilidad
  3. Desarrollo ágil con base de datos sin esquemas
    1. Al usar JSON/BSON es fácil de codificar y administrar
  4. Escalabilidad horizontal más facil
    1. Es una solución para sistemas que requieren escalar horizontalmente sobre varios servidores.
    2. La funcionalidad de autosharding permite escalar tu cluster agregando mas equipos sin necesidad de dar de baja el servicio.

En realidad no estamos quitando todo el trabajo que ya se ha hecho con las bases de datos relacionales porque en muchas cosas como la creación de indices, llaves primarias, consultas dinámicas y actualizaciones, por mencionar algunas,  se tiene que hacer los mismo, salvo que se busca tener las ventajas arriba descritas.

La gente de apache que desarrolla CouchDB mencionan que los esquemas relacionales funcionarán en algunos casos mientras que los esquemas no-SQL funcionarán en otros.




El modelo de datos de MongoDB considera lo siguiente:
  • Un sistema mongo contiene un conjunto de bases de datos.
  • Una base de datos (database) contiene un conjunto de colecciones.
  • Una colección (collection) contiene un conjunto de documentos.
  • Un documento (document) es un conjunto de campos.
  • Un campo (field) es un par llave - valor.
  • Una llave (key) es un nombre en forma de cadena.
  • Un valor (value) es:
    • un tipo de dato básico, string, integer, float, timestamp, binary, etc.,
    • otro documento, ó
    • un arreglo de valores

El lenguaje de consulta

Al tratar con objetos json la estructura de un nombre podria ser: {nombre: 'Sebastian', paterno: 'Morales'}, esta estructura se puede usar por ejemplo para buscar todos los documentos (registros) de una colección (tabla) que empaten con el nombre "Sebastian Morales", pero también podemos hacer lo siguiente:
  • {nombre.paterno: 'Morales'}, para obtener los que tengan apellidos 'Morales'.
  • {nombre.paterno: /^M/}, para obtener los que tengan apellidos que inicien con 'M'
  • {keywords: 'tecnico'}, para los documentos con 'tecnico' dentro del contenido del arreglo
  • {keywords: {$in:['tecnico', 'licenciado']}, para los documentos con 'tecnico' o licenciado dentro del contenido del arreglo.
Si tenemos muchos documentos en una colección y queremos mejorar la velocidad de búsqueda de las consultas, crearemos índices comose muestra abajo, pero hay que tomar en cuenta que se ocupa mas espacio y reduce la velocidad de los 'update'.
  • ensureIndex({nombre.apellido:1})
  • ensureIndex({keywords: 1})

Instalación y primeros ejemplos

Aunque los procesos de instalación son diferentes para cada S.O. yo presentaré el que realicé en Linux Mint.  Debo comentar que el sitio de MongoDB recomienda que se descargue la última version de sus servidores ya que los repositorios de Debian o Ubuntu no se encuentran del todo actualizados, no obstante para propositos de esta entrada nos basta seguir lo siguiente:

sudo apt-get install mongodb

Entre los comandos que se instalarán se encuentran mongod (servidor) y mongo (cliente).  Este último debe ser el usado para entrar a la consola y ejecutar consultas al servidor.

mongo
> db.alumno.save({nombre:'julian', paterno:'rodriguez', edad:12, grupo:'2A'})
> db.alumno.find()
{ "_id" : ObjectId("4f99d713b16869a4f4d5abd9"), "nombre" : "julian", "paterno" : "rodriguez", "edad" : 12, "grupo" : "2A" }
> help

Con db.alumno.save() creamos la colección alumno y agregamos el primer documento con el nombre de julian, luego lo consultamos con db.alumno.find() y para ver mas ayuda sobre los comandos ejecuta help.

Por defecto, el comando mongo se conecta a una base de datos llamada "test" en localhost, por eso al ejecutar el comando mongo, verían algo como esto:
wdonet@wdonet-mint12 ~ $ mongo
MongoDB shell version: 1.8.2
Thu Apr 26 17:06:35 *** warning: spider monkey build without utf8 support.  consider rebuilding with utf8 support
connecting to: test
> db

test

> use miPropiaBD
switched to db miBD
>
db
miPropiaBD

Usamos el comando use para poder cambiar la base de datos y lo comprobamos con el comando db o con show dbs.  Esto no crea inmediatamente la BD, sino hasta que por primera vez le insertas datos. El comando show no mostrará la nueva BD hasta que insertes datos.  Lo mismo sucede con las colecciones.

En MongoDB no hay campos predefinidos (lo que serían columnas en un RDBMS), tampoco hay esquemas definidos para dichos campos por lo que sus tipos de dato pueden variar y las colecciones pueden guardar diferenets campos.

> j = { nombre : "roberto"};
{ "nombre" : "roberto" }
> t = {edad : 30}
{ "edad" : 30 }
> db.nuevaColeccion.save({j, t})
Thu Apr 26 19:25:15 SyntaxError: invalid object initializer (shell):1
> db.
nuevaColeccion.save(j)
> db.
nuevaColeccion.save(t)
> db.
nuevaColeccion.find()
{ "_id" : ObjectId("4f99e77c00745aa18f47cb08"), "nombre" : "oswaldo" }
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }
>



Cada vez que se inserta un documento en la colleccion, se crea un identificador del objeto "_id" que es diferente para cada documento, funciona como una llave primaria.

También es de observar que los ';' son para terminar una instrucción, pero si solo es una por línea, no son necesarios.  Otro conveniente es que podemos usar ciclos y operaciones matemáticas como el que sigue:

> for (var i = 0; i <= 5; i++) db.nuevaColeccion.save({x: i*i, y: i+i});
> db.
nuevaColeccion.find()
{ "_id" : ObjectId("4f99e77c00745aa18f47cb08"), "nombre" : "
roberto" }
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0a"), "x" : 0, "y" : 0 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0b"), "x" : 1, "y" : 2 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0c"), "x" : 4, "y" : 4 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0d"), "x" : 9, "y" : 6 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0e"), "x" : 16, "y" : 8 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0f"), "x" : 25, "y" : 10 }


El comando find() devuelve un objeto cursor, pero esta limitado a 20 resultados por pagina, si tuvieramos más de 20 documentos y quisieramos ver la siguiente página de resultados, deberíamos ejecutar "it" para que el shell itere automáticamente sobre el cursor

> it

Podemos jugar un poco con un cursor mediante metodos hasNext() o forEach(), e imprimimos con el método printjson().

> var cursor = db.nuevaColeccion.find();
> while (cursor.hasNext()) printjson(cursor.next())
{ "_id" : ObjectId("4f99e77c00745aa18f47cb08"), "nombre" : "roberto" }
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0a"), "x" : 0, "y" : 0 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0b"), "x" : 1, "y" : 2 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0c"), "x" : 4, "y" : 4 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0d"), "x" : 9, "y" : 6 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0e"), "x" : 16, "y" : 8 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0f"), "x" : 25, "y" : 10 }
>
> db.
nuevaColeccion.find().forEach(printjson);
{ "_id" : ObjectId("4f99e77c00745aa18f47cb08"), "nombre" : "roberto" }
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0a"), "x" : 0, "y" : 0 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0b"), "x" : 1, "y" : 2 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0c"), "x" : 4, "y" : 4 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0d"), "x" : 9, "y" : 6 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0e"), "x" : 16, "y" : 8 }
{ "_id" : ObjectId("4f99e96600745aa18f47cb0f"), "x" : 25, "y" : 10 }
>
> var cursor = db.nuevaColeccion.find();
> printjson(cursor[1])
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }

 

Los resultados del cursor se almacenan en memoria, por lo que hay que tener cuidado con resultados con muchos documentos.

Por último, para el propósito de introducción de esta entrada, podemos convertirlo en un verdadero arreglo como sigue:



> var arreglo = db.nuevaColeccion.find().toArray();
> printjson(
arreglo[1])
{ "_id" : ObjectId("4f99e77e00745aa18f47cb09"), "edad" : 30 }


Para salir:

> exit;



Fuentes:

No hay comentarios:

Publicar un comentario

Que opinas sobre esta publicación?