Últimamente he venido interesándome por el mundo de las bases de datos noSQL y más concretamente sobre MongoDB, que es una de las más utilizadas en entornos de producción, y en empresas como Foursquare y Codecademy. Este post pretende ser una introducción a MongoDB (MongoDB para principiantes), su modelo de datos, sus comandos de shell y sus consultas.
MongoDB (del inglés «humongous», enorme) es una base de datos NoSQL, que en vez de guardar los datos en tablas, como en las bases de datos relacionales, se almacenan en estructuras de datos JSON.
Comenzó a desarrollarse en octubre de 2007 por la compañía 10gen. En 2009 se lanzó como producto independiente publicado con licencia de código abierto. Actualmente hay versiones para Windows, Linux, OSX y Solaris.
DataModel
Una instalación de MongoDB alberga una o varias bases de datos,y cada una de ellas un conjunto de coleccciones. A su vez cada colección alberga uno o varios (pudiendo ser un número enorme de ellos) documentos. Un documento es cada registro existente en una colección y la unidad básica de datos en MongoDB. Son análogos a objetos JSON pero en base de datos se almacenan en un formato más rico conocido como BSON (Binary JSON). La estructura de un documento se compone de pares «clave-valor«, separadas por «:»:
{ field1: value1, field2: value2, field3: value3, ... fieldN: valueN }
Cada valor, a su vez, puede ser otro documento. A continuación se muestra un ejemplo:
{ "_id": ObjectId("4efa8d2b7d284dad101e4bc7"), "Last Name": "Johnson", "First Name": "Michael", "Age": 29, "Address": { "Street": "1 chemin des Loges", "City": "VERSAILLES" } }
El campo «_id» es único en la colección. Si no lo incluimos en el documento a la hora de insertarlo en la colección, MongoDB asignará uno por defecto.
Los documentos utilizan un esquema dinámico. Esto quiere decir que los documentos dentro de una misma colección no necesitan tener los mismos campos ni estructura, y los campos comunes pueden tener distintos tipos de datos. Esta flexibilidad permite elegir el modelado de datos que más se adapte a la aplicación y a sus requisitos de rendimiento. El siguiente documento podría almacenarse junto al anterior ejemplo en la misma colección:
{ "_id": ObjectId("d2b7d24efa884de4bc7ad101"), "Last Name": "Allison", "First Name": "Robert", "Hobbies": ["music", "sports"] }
Instalación
Lo primero es descargar el software desde la página correspondiente. Existen versiones para los sistemas operativos más utilizados (Windows, Linux, OSX y Solaris) en versiones de 32 y 64 bits. La versión de 32 bits tiene el problema de estar limitada a 2Gb de datos entre todas las colecciones que almacene. Tras descargarnos el fichero zip o tgz, lo descomprimimos en el sistema de ficheros. En la carpeta principal de la instalación existirá una carpeta bin con las utilidades de la base de datos.
Para ejecutar MongoDB es necesario que exista en el directorio raíz (C:\ en Windows) la siguiente ruta C:\data\db como destino de los datos. En el momento de lanzar la ejecución de MongoDB podemos modificar la ubicación de esta ruta. A continuación ejecutamos desde línea de comandos
C:\mongodb\bin\mongod.exe
Este comando lanzará el proceso de MongoDB y si todo va bien aparecerá el mensaje «waiting for connections». Para especificar otra ruta para los datos lo haremos indicando el directorio de datos tras el parámetro –dbpath:
C:\mongodb\bin\mongod.exe --dbpath d:\test\mongodb\data
También es posible ejecutar MongoDB como un servicio de Windows. Para instalarlo como servicio
Mongo Shell
Desde otra consola de comandos ejecutamos el siguiente comando:
C:\mongodb\bin\mongo.exe
Mongo shell (mongo.exe) conectará con el proceso mongod.exe que está ejecutando en la máquina local en el puerto 27017 por defecto. Para comprobar que está todo correcto ejecutamos los siguientes comandos:
db.test.save( { a: 1 } ) db.test.find()
El comando save ejecutado sobre la colección test, guarda el documento JSON pasado como parámetro a la función. Después de ejecutar el comando find(), obtenemos el único documento de la colección. A ese documento, como ya habíamos apuntado anteriormente MongoDB le añade un id único:
{"_id" : ObjectId("52fa4fe0d5ac743a52aa98e1"), "a" : 1 }
Por defecto usamos la base de datos test. Para ver las bases de datos utilizamos los siguientes comandos:
> show dbs curso 0.203125GB enron 1.953125GB local 0.078125GB test 0.203125GB > use enron switched to db enron
Junto al nombre de la base de datos, aparece el tamaño que ocupa en el sistema de ficheros. El comando use enron, cambia la base de datos de trabajo y sobre la que se ejecutan las operaciones de la shell. Para visualizar las colecciones de una base de datos ejecutamos el comando:
> show collections messages system.indexes
Hay que señalar que no existe ningún comando para crear una base de datos, pero podemos hacerlo con el comando use nombrenuevadb, e insertar un documento en una colección con save. MongoDB creará tanto la base de datos como la colección:
> use customers switched to db customers > db.clientes.save({"nombre":"juan"}) > show dbs curso 0.203125GB customers 0.203125GB enron 1.953125GB local 0.078125GB test 0.203125GB > db.clientes.find() { "_id" : ObjectId("531995937efc2c88b31af841"), "nombre" : "juan" }
Operaciones CRUD
Definimos operaciones CRUD como las operaciones para crear, leer, actualizar y borrar (Create, Read, Update and Delete) .
Consultas
Para realizar queries, MongoDB provee el método db.collection.find(), siendo collection el nombre de la colección a consultar:
Obtener todos los documentos de una colección
db.inventory.find()
Obtener todos los documentos de una colección que cumplen el valor para el tipo especificado {<field>:<value>}. Se puede indicar más de un valor para el campo con $in
db.inventory.find({tipo:"juguetes"}) db.inventory.find({tipo: { $in: ['comida', 'juguetes'] }})
Obtener todos los documentos de una colección que cumplen más de un valor (AND) para los tipos especificados {<field>:<value>}. Se pueden comparar valores con $lt (menor que) y $gt (mayor que).
db.inventory.find({tipo:"juguetes", precio: { $lt: 9.95 }})
Se pueden configurar queries con operadores OR.
db.inventory.find( { $or: [ { qty: { $gt: 100 } }, { price: { $lt: 9.95 } } ] } )
Y combinaciones de AND y OR.
db.inventory.find( { type: 'food', $or: [ { qty: { $gt: 100 } }, { price: { $lt: 9.95 } } ] } )
Para retornar unos campos específicos en la consulta, los indicamos como segundo parámetro del método find. En el ejemplo sólo retorna los campos item y qty:
db.inventory.find( { type: 'food' }, { item: 1, qty: 1 } )
Para indicar que un campo no queremos que se retorne en la consulta en vez de un 1 asignamos un 0.
db.inventory.find( { type: 'food' }, { item: 1, qty: 1, _id:0 } )
Si queremos que devuelva todos los campos excepto los excluidos, únicamente indicamos éstos.
db.inventory.find( { type: 'food' }, { qty: 0 } )
Inserciones
Se pueden insertar documentos a través de varios métodos. El primero con la llamada al método insert() con el documento a insertar
db.inventory.insert( { _id: 10, type: "misc", item: "card", qty: 15 } )
El segundo método es a través de la llamada al método update() con el flag upsert:true
db.inventory.update( { type: "book", item : "journal" }, { $set : { qty: 10 } }, { upsert : true } )
Intenta actualizar el registro Si no especificamos la clave _id, Mongo nos creará una por defecto que además es única
El tercer método es invocando al método save() con el documento a insertar. Si el documento pasado no contiene _id, mongo creará igualmente una clave única.
db.inventory.save( { type: "book", item: "notebook", qty: 40 } )
Actualizaciones
El método update() actualiza un único documento que coincide con el criterio de búsqueda pasado como primer parámetro, con los datos pasados en el documento del segundo parámetro. Podemos pasar la opción multi : true para indicar que se guarden varios.
db.inventory.update( { type : "book" }, { $inc : { qty : -1 } }, { multi: true } )
También se puede actualizar un documento por su clave «_id» mediante el método save()
db.inventory.save( { _id: 10, type: "misc", item: "placard" })
Borrados
El borrado de todos los documentos se hace con remove() o drop()
db.inventory.remove() db.inventory.drop()
Para el borrado de documentos que coinciden con un criterio de búsqueda
db.inventory.remove( { tipo: "comida" } )
Para profundizar en éste y otros temas podemos acudir al manual en línea de MongoDB o apuntarse a alguno de sus cursos gratuitos.