logoCoderhouse.png
Ë
By Oscar Lopez • January 27, 2016

Mongodb | Aprende a crear una base de datos No SQL

Introducción

Mongodb es una base de datos No SQL orientada a documentos (BSON/JSON). Para poder entender porque mongodb es NoSQL, es necesario saber qué es SQL.

SQL significa Structured Query Language o lenguaje de consultas estructurado. SQL permite almacenar datos basándose en un concepto matemático llamado algebra relacional, por lo que también se las conoce a las base SQL como bases de datos relacionales.

Son relacionales porque utilizan las relaciones entre conjuntos(tablas) para filtrar los datos que se necesiten para determinada situación.
Debido a que los problemas evolucionaron, las soluciones y los sistemas también. Hay situaciones donde el uso de SQL es problemático o por lo menos no se adapta a ciertos escenarios. Uno de los casos más evidentes es en las aplicaciones real time.

Un escenario No SQL

Hacemos una app que utilice la API de Twitter con una base SQL para hacer estadísticas. Nuestra app funciona unos meses y de repente deja de funcionar, investigamos que pasó y nos damos cuenta de que twitter cambió el objeto tweet y la base de datos rechazaba el insert en la tabla tweets. Si bien se puede hacer bien el sistema con la base SQL, no es lo más natural, no es fluido.

Un tweet puede cambiar con el paso del tiempo. Twitter no te va a notificar cada vez que hace un cambio, o por lo menos tu aplicación no debería contar con eso. Por ende, si quisieras que tu sistema soporte el almacenamiento de  tweets constantemente, sin romper el programa, podrías utilizar una base de datos No SQL y almacenar los documentos JSON tal cual vienen desde la API de twitter.

Mongodb

Mongodb es una base de datos orientada a documentos. Esto significa que almacena objetos de tipo JSON (técnicamente Binary JSON). Está basada en el motor V8 de google (chrome) y permite realizar operaciones (insert, update, remove,etc) con javascript. Esto hace que mongodb sea gran candidato a ser la db de una aplicación web donde todas las capas son con JavaScript.

También se puede utilizar con otros lenguajes como Java y .Net con sus respectivos drivers.

Principales características

  • Almacena documentos JSON(Binary JSON).
  • Es Schemaless.
  • Se ejecutan operaciones con JavaScript.
  • Posee tolerancia a fallos, clustering, réplicas.
  • Es No SQL.

Mongodb es Schemaless

No tener schema significa que no hay una estructura fija que le de forma a los documentos que almacenamos, estos pueden tener diferentes esquemas, pueden variar sus propiedades. Si bien esto es una gran ventaja, tampoco hay que abusar de ella porque nuestra base deja de ser eficiente al momento de realizar búsquedas.

Por ejemplo, un tweet puede variar en que tenga o no geo localización, pero siempre va a tener un id de usuario, un texto y una imagen asociada. El esquema varía pero la escencia es la misma.

Mongodb CRUD

Create

Empecemos con algo de práctica. Para conocer las operaciones de mongodb podemos hacer un CRUD (CREATE, READ, UPDATE, DELETE).
Para almacenar datos en mongodb es necesario crear una base de datos. Para ello abrimos la terminal y ejecutamos el comando mongo. Si todavía no instalaste Mongo en tu computadora ¡es un gran momento para hacerlo! Encuentra como hacerlo para tu sistema operativo acá

Screen Shot 2016-01-25 at 10.09.09

Para crear una base de datos, solo hace falta ejecutar el comando use

Screen Shot 2016-01-25 at 10.10.58

En este caso creamos una base que se llama travel.

Una vez que tenemos la base de datos, es necesario crear una collection para almacenarlos. Una collection es una entidad que contiene un conjunto de objetos JSON o documentos.

Por el simple hecho de insertar un documento, se crea una collection.

<code>&gt; db.hotels.insert({name:"Hotel Prueba", stars:5, location:{ city: "Buenos Aires",geo:{ long:-72.
27049999999997, lat:-50.3402} }, checkin:"11:00pm",checkout:"15:00pm" });</code>

Screen Shot 2016-01-25 at 10.18.24

Eso fue la C del CRUD.

El comando es insert y la estructura es la siguiente:

<code>db.collection.operation(objects)</code>

db.hotels.insert({...}) almacena en la db travel, collection hotels un documento JSON que representa a un hotel.

Read

Los hoteles en esta collection pueden ser diferentes, algunos pueden tener mas propiedades como por ejemplo, información acerca de sus amenities, restaurante, spa. También podría tener imágenes de sus habitaciones, tipos de habitaciones, etc.

Para consultar el hotel insertado seguimos la misma estructura, db.collection.operation()

En este caso podemos hacer una consulta que nos devuelva todos los hoteles.

<code>db.hotels.find()</code>

Screen Shot 2016-01-25 at 10.24.19

Este comando trae todos los documentos de la collection. Si quisiera podría pedir todos los hoteles 5 estrellas. Para ello puedo ejecutar la siguiente consulta.

<code>db.hotels.find({stars:5})</code>

Screen Shot 2016-01-25 at 10.26.13

Como se ve en la consulta, es un simple JSON. {stars:5} significa que buscará todos los objetos donde coincida que la propiedad stars sea igual a 5.

Si necesito hacer una consulta un poco más exigente, puedo consultar por ejemplo, todos los hoteles de 3 estrellas o más. Para esto, es necesario utilizar operadores, como >=(mayor igual), <=(menor igual), !(not).

https://docs.mongodb.org/manual/reference/operator/query/gt/

<code>db.hotels.find( {stars: {$gte:3}} )</code>

Screen Shot 2016-01-25 at 10.33.00

Si quiero agregar mas condiciones, solo hay que colocar las propiedades que quiero filtrar. Si quiero todos los hoteles mayores de 3 estrellas y que estén en Buenos Aires, tendría que hacer la siguiente consulta.

<code>db.hotels.find( {stars: {$gte:3}, "location.city":"Buenos Aires"  } )</code>

Screen Shot 2016-01-25 at 10.37.05

Hay otro detalle a tener en cuenta, la ciudad es una propiedad dentro de un objeto, por eso hay que colocar el path de la propiedad que quiero filtrar. “location.city”(entre comillas dobles), es el path de la ciuidad del hotel.

Un objeto JSON puede contener propiedades de valores primitivos (strings, integers, boolean), otros objetos y arrays.

Update

Mongodb permite consultar elementos dentro de los arrays que pertencen a un objeto. En mongodb no se puede almacenar un array directamente, siempre tiene que pertencer a un objeto.

Para operar con arrays existen operadores como $in, $push, $pop, $addToSet que permite hacer operaciones similares a las que se hacen con cualquier lenguaje de programación.

Para agregar propiedades a un documento que existe en la collection, es necesario ejecutar la operación update. La estructura de esta es la siguiente:

<code>db.collection.update({query}, {update},{options})</code>

Agreguemos un array que contenga los tipo de habitaciones del hotel al hotel que insertamos previamente.

El comando sería el siguiente:

<code>db.hotels.update({"_id" : ObjectId("56a62092f1ec5d6ee655f889")},{rooms: [{ name: "Habitación 
Estandar", max:2, amenities:['Aire Acondicionado','TV','WIFI'] , category:"Standard" }] })</code>

Screen Shot 2016-01-25 at 10.53.57

Al ejecutar el update podemos ver el WriteResult, este indica el resultado de la operación. nMatched significa que la query del update coincidió con un documento y un documento fue modificado.

La query del update fue por id, al insertar un documento en una collection si no se especifica la propiedad _id, mongodb crea un _id automáticamente. NO pueden existir documentos sin un _id, todos los documentos son distintos.
Si consultamos el hotel por id, podemos ver el array de rooms.

Screen Shot 2016-01-25 at 10.58.43

Como se ve en el resultado, perdimos toda la data anterior del hotel, solo se ve el _id y las rooms. Esto sucede porque por default el update sobreescribe el objeto de la query. Para agregar propiedades a un objeto existente se utiliza el operador $set

db.hotels.update({"_id" : ObjectId("56a62abbf1ec5d6ee655f88a")},{$set: {rooms:
[{ name: "Habitación Estandar", max:2, amenities:['Aire Acondicionado','TV',
'WIFI'] , category:"Standard" } ] }})

Screen Shot 2016-01-25 at 11.02.27

Como se ve en el update, se agrega el $set envolviendo un objeto con la propiedad a agregar.

Cuando consulto por el hotel, aparecen todas las propiedades que tenía más la nueva propiedad room.

Para agregar rooms al array puedo utilizar el operador $push y para remover el último elemento insertado puedo utilizar $pop.

Por ejemplo, agreguemos una nueva habitación.

<code>db.hotels.update({"_id" : ObjectId("56a62abbf1ec5d6ee655f88a")},{$push: {rooms: [ { name: 
"Habitación Triple Standard", max:3, amenities:['Aire Acondicionado','TV','WIFI'] , category:"Standard" }] }})
</code>

Screen Shot 2016-01-25 at 11.08.24

Screen Shot 2016-01-25 at 11.08.50

Como se ve en la imagen, hay un error en el array rooms. El primer elemento es un objeto y el segundo es un array. Para solucionar esto puedo ejecutar el update con $pop y borrar el último elemento.

Screen Shot 2016-01-25 at 11.17.21

Como se ve en la imágen, hay un error en el array rooms. El primer elemento es un objeto y el segundo es un array. Para solucionar esto puedo ejecutar el update con $pop y borrar el último elemento.

Un detalle a tener en cuenta con la operación update es que por default no actualiza todos los elementos que coinciden con la query. Supongamos que quiero agregarle a todos los documentos de la collection hotels una propiedad type para indicar que es un hotel y no un hostel o una cabaña.

En un principio sería el siguiente comando:

<code>db.hotels.update({}, {$set:{type:”HOTEL”}})</code>

El comando está bien pensado, la query es sobre todos los objetos y la operación es agregar una propiedad ($set) que setee type: HOTEL. Lo que va a suceder es que mongodb va a actualizar el primer objeto que coincida con la query. Para que actualice todos es necesario agregar la option {multi:true}

<code>db.hotels.update({}, {$set:{type:”HOTEL”}}, {multi:true})</code>

Delete

Para borrar documentos se utiliza la operación remove. La estructura es la siguiente:

<code>db.collection.remove({query})</code>

Antes de ejecutar un remove, les recomiendo que hagan un find de lo que van a borrar para chequear que es exactamente lo que quieren borrar.

Si quieren borrar todos los objetos de una collection pero no quiere borrar esta última pueden hacer lo siguiente:

<code>db.collection.remove({})</code>

Si quieren borrar los hoteles que cumplan cierta condición, se utilizan los mismos operadores que la operación find. Se puede borrar con condiciones y por _id.

Mongodb + Node.js

Para poder utilizar mongodb desde Node.js es necesario contar con un Driver. Este driver nos permite ejecutar las mismas operaciones que en la terminal. En mi caso utilizaré mongojs

Como las consultas en mongodb están hechas en Javascript, las puedo transladar como están a un programa en node.js. El único cambio que hay que hacer es agregarle un callback.

Veamos un ejemplo.

var mongojs = require("mongojs");

var db = mongojs("mongodb://localhost:27017/travel",["hotels"]);

db.hotels.find({},function(err,docs){
if(err){
console.log("Ocurrió un error al ejecutar la consulta",err);
}else{
console.log(docs);
}
});

Screen Shot 2016-01-25 at 11.42.18

Así como hicimos un find, podemos hacer cualquier otra operación como las que vimos anteriormente.

Conclusiones

Mongodb es una base de datos que permite almacenar documentos, es schemaless y posee operaciones y operadores que se ejecutan con JavaScript que permiten interactuar con la data.

Las operaciones son insert, find, update y remove. Estas pueden contener operadores como $set, $unset, $push, $pop y hay que tener en cuenta que el update no actualiza todo por default.

Es muy fácil realizar consultas con mongodb porque en un principio, solo tiene que coincidir el objeto query con las propiedaes que quiero filtrar.

Luego pasar esto a una aplicación javascript con nodejs es casi copiar y pegar la consulta.
Con lo que vimos podemos crear un programa con nodejs, conectarse a una base de mongo y hacer las mismas operaciones.

¿Que les pareció este tutorial? Queremos ver en qué proyectos utilizan Mongodb :)