Mostrando entradas con la etiqueta coleccio nes. Mostrar todas las entradas
Mostrando entradas con la etiqueta coleccio nes. Mostrar todas las entradas

martes, 9 de abril de 2013

¡A enmongarse toca!

Después de un primer contacto con NODE+MONGODB+EXPRESS y antes de meterle mano a mongoJS, debería trastear con mongoDB directamente y hacerme una idea de cómo tendría que crear la estructura de registros (documentos creo que se llaman) necesaria para KomanderTPV.

Ver cómo se selecciona por criterios, hacer consultas complejas, alterar tablas y ese tipo de cosas que uno esta acostumbrado a hacer en una base de datos SQL (MySQL en mi caso).

Siento desilusionar a todos aquellos que hayan pensado que vamos a ponernos púos de monguis, tal y como el título del post pueda sugerir. Espero que al menos la banda sonora no te defraude.

MANOS A LA OBRA

Por lo pronto me voy a http://www.mongodb.org para hacer el pequeño tutorial que ofrecen online. Recuerdo que lo hice una vez porque me llamo la atención.. Pero no recuerdo mucho como iba y no tenía un mongo en mi máquina para practicar.

En el punto número 2 del tutorial aclaran que MongoDB guarda los datos en forma de documentos, los cuales son lo mismo que un objeto en JavaScript.

2. Documents
MongoDB is a document database. This means that we store data as documents,
which are similar to JavaScript objects. Here below are a few sample JS objects:
  var a = {age: 25}; 
  var n = {name: 'Ed', languages: ['c', 'ruby', 'js']}; 
  var student = {name: 'Jim', scores: [75, 99, 87.2]}; 

Así por encima, se me ocurre:

var plato = { nombre: 'Churrasco', mods: ['Patatas', 'Ensalada']};

Supongo que disponer de un array dentro de un registro, es una ventaja si lo comparo con SQL, ya que para hacerlo en SLQ tendría que tener dos tablas y relacionarlas: Platos y Modificadores. Pero eso ya se verá... no quiero precipitarme, ya que aún no se nada.

Este es el resultado de ejecutar la sentencia anterior:

{
 "nombre" : "Churrasco Argentino",
 "mods" : [   "Patatas",   "Ensalada" ]
 }

Un objeto 'plato'. Churrasco Argentino el cual podrá ir acompañado de Patatas o con Ensalada (ufffff, no comment)

El tercer paso muestra como guardar un documento (registro) dentro de una colección (tabla). 


Guarda un documento en la colección 'scores':
db.scores.save({a:99});

Muestra los documentos de la colección 'scores';
db.scores.find();

(Estoy tratando de que me funcione el save(), pero parece que no se guardan los documentos... acabaré de leer  el minitutorial por encima y al lio en mi máquina)

Se acabo el minitutorial... ahora a practicar.


Desde una shell con mongo, creo la db  donde guardaée las colecciones para KomanderTPV:

> use km
switched to db km

El comando use cambia a la db seleccionada y encaso de que no exista, la crea.

Para crear una colección simplemente inserto un documento en la colección con el nombre deseado:


> db.articulos.insert({nombre: 'Churrasco'});

Ahora si hago un find():

> db.articulos.find();
{ "_id" : ObjectId("516329924680b862f0ced8c9"), "nombre" : "Churrasco" }
>


Ya tengo mi db, mi primera colección y mi primer documento.
Añadiré un par de ellos más...

> db.articulos.insert({nombre: 'Kobe'});



> var mas_articulos = [{nombre: 'Solomillo Ternera'},{ nombre: 'Chuleton de Buey'}];
> db.articulos.insert(mas_articulos);


Ya tengo varios artículos añadidos a mi db. Todos platos de carne buena y jugosa. Hace falta algo de pescado. Tanta carne...


> var algunos_pescados = [{nombre: 'Dorada'},{ nombre: 'Urta'}];
> db.articulos.insert(algunos_pescados);


Consultando la colección 'articulos' veo que tengo 6 distintos:


> db.articulos.find();
{ "_id" : ObjectId("516329924680b862f0ced8c9"), "nombre" : "Churrasco" }
{ "_id" : ObjectId("51632a714680b862f0ced8ca"), "nombre" : "Kobe" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cb"), "nombre" : "Solomillo Ternera" }

{ "_id" : ObjectId("51632b5b4680b862f0ced8cc"), "nombre" : "Chuleton de Buey" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8cd"), "nombre" : "Dorada" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8ce"), "nombre" : "Urta" }


Pero cuatro de ellos son platos de carne y los otros dos son pescados. Debería agregar un campo al documento que me permita diferenciar la carne del pescado. Lo llamaré 'familia'.

Pero que hago? Inserto familia directamente artículo por artículo? Altero el documento para que tenga un campo familia vacio? Cual es la mejor forma?

Utilizando $set me ha añadido la familia 'carne' al articulo con nombre Churrasco:



> db.articulos.update({nombre: 'Churrasco'},{'$set': {'familia':'Carne'}});
> db.articulos.find();
{ "_id" : ObjectId("51632a714680b862f0ced8ca"), "nombre" : "Kobe" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cb"), "nombre" : "Solomillo Ternera" }

{ "_id" : ObjectId("51632b5b4680b862f0ced8cc"), "nombre" : "Chuleton de Buey" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8cd"), "nombre" : "Dorada" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8ce"), "nombre" : "Urta" }
{ "_id" : ObjectId("516329924680b862f0ced8c9"), "familia" : "Carne", "nombre" :
"Churrasco" }

 se debe cambiar de uno en uno? No lo sé. Lo comprobaré...

Para modificar la clave de en todos los documentos el selector debe estar vacío. Además, el último parámetro de la función update (multi) debe estar a true:
> db.articulos.update({},{'$set':{'familia': ""}},false,true);

> db.articulos.find();
{ "_id" : ObjectId("516329924680b862f0ced8c9"), "familia" : "", "nombre" : "Churrasco" }
{ "_id" : ObjectId("51632a714680b862f0ced8ca"), "familia" : "", "nombre" : "Kobe" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cb"), "familia" : "", "nombre" : "Solomillo Ternera" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cc"), "familia" : "", "nombre" : "Chuleton de Buey" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8cd"), "familia" : "", "nombre" : "Dorada" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8ce"), "familia" : "", "nombre" : "Urta" }

En este caso, al realizar el anterior update, ha machacado la familia que estaba en el artículo Churrasco.

Mi gran duda ahora es si debería crear una colección 'familias' la cual estará relacionada con 'articulos' mediante la id. No se cúal es la metodología en este caso. Así que a buscar algo de info.

EN la pagina de mongo, leo sobre el modelado de datos...
http://docs.mongodb.org/manual/tutorial/model-embedded-one-to-one-relationships-between-documents/
http://docs.mongodb.org/manual/tutorial/model-embedded-one-to-many-relationships-between-documents/
http://docs.mongodb.org/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/
http://docs.mongodb.org/manual/tutorial/model-data-for-atomic-operations/

http://www.10gen.com/presentations/mongodb-melbourne-2012/schema-design-example

Después de leer sobre el modelado de datos en mongoDB realmente no tengo clara la idea. Todo depende de como se vayan a escribir y leer los datos en tu aplicación. La forma en que se usarán los datos.

SI que se recomienda embeber todo en un documento, ya que obtiene todo en una sola consulta... pero es más difícil de manipular.. No sé realmente. Leeré un poco más y lo practicaré.

...

Finalmente comenzaré creando colecciones distintas para cada cosa... Quizás lo haga así por mi mentalidad SQL, pero de todas formas, no me gusta la repetición de datos, la cual supongo es una mala práctica.

Probaré, aunque ya ni me acuerdo del nombre que le puse a la base de datos. Cerré las ventanas de mongo y con tanta información ya no recuerdo por donde iba...

Bueno, abro mi mongo, y reviso cuales son las dbs existentes:

> show dbs
blog    0.0625GB
km      0.0625GB
local   0.03125GB

Ahora ya me acuerdo, mi db es 'km'

> use km
switched to db km

Y, cual era la coleccion??

> show collections
articulos
system.indexes

AH sí... articulos... asi con para ver las dbs y las colecciones que tenemos, podemos usar el comando 'show' seguido de lo que queremos ver:

> show dbs
> show collections

Bueno.. a lo que vamos. Voy a crear una colección llamada 'familias', cuyo indice se insertará como valor en la clave 'familia' de los documentos 'articulos'. Pero esta vez pondré yo la id del documento:

> db.familias.insert({_id:1, nombre:'Carnes'});
> db.familias.find();
{ "_id" : 1, "nombre" : "Carnes" }

Por lo pronto ya no tengo una id tan larga... Lo que sí es largo, es tener que estar escribiendo 'db.coleccion'...

> var f = db.familias;
> f.find();
{ "_id" : 1, "nombre" : "Carnes" }

Vale. Es más fácil escribir 'f' (de familia) que tener que poner 'db.familias'. Vamos progresando...

> f.insert({_id: 2, nombre:'Pescado'});

Ya tenemos articulos y familias. Vamos a modificar los documentos de la colección articulos para que cada uno apunte a su tipo de familia:

> var a = db.articulos;
> a.update({nombre:'Churrasco'},{'$set':{familia:1}});


> a.update({nombre:'Kobe'},{'$set':{familia:1}});
> a.update({nombre:'Solomillo Ternera'},{'$set':{familia:1}});
> a.update({nombre:'Chuleton de Buey'},{'$set':{familia:1}});
> a.update({nombre:'Dorada'},{'$set':{familia:2}});
> a.update({nombre:'Urta'},{'$set':{familia:2}});
> a.find();
{ "_id" : ObjectId("516329924680b862f0ced8c9"), "familia" : 1, "nombre" : "Churrasco" }
{ "_id" : ObjectId("51632a714680b862f0ced8ca"), "familia" : 1, "nombre" : "Kobe" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cb"), "familia" : 1, "nombre" : "Solomillo Ternera" }
{ "_id" : ObjectId("51632b5b4680b862f0ced8cc"), "familia" : 1, "nombre" : "Chuleton de Buey" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8ce"), "familia" : 2, "nombre" : "Urta" }
{ "_id" : ObjectId("51632cfe4680b862f0ced8cd"), "familia" : 2, "nombre" : "Dorada" }



OK, ahora viene lo bueno porque para ver el nombre de la familia del articulo Churrasco yo pensaría:

SELECT familias.nombre FROM familias INNER JOIN articulos ON familias._id = articulos.familia WHERE articulos.nombre = 'Churrasco'

A ver como cambio mi mentalidad para esto...

Buenooo... tras leer en varios post sobre el tema, todo desemboca en la misma respuesta:

OPEN YOUR MIND!!

No simplificar en las colecciones, es decir, no debería crear una colección para cada tabla y que esta se relacione con la otra y tal y cual... No debería pensar relacionalmente... Me cuesta pero debo hacerlo así... Lo mejor es que haga lo contrario a lo que creo que es lo mejor. Dividir un documento en distintas colecciones ralentizará el sistema.

Así que borrare mi db 'km' y comenzaré de nuevo con otra mentalidad.

> use km
switched to db km
> db.dropDatabase();
{ "dropped" : "km", "ok" : 1 }

CONCLUSIÓN

Hasta este punto y con lo visto, creo que he recorrido algunos pasos. De sobra sé, en el contexto que me toca, que por muchos pasos que dé, nunca llegaré al final. Pero seguro que estaré más lejos que al principio.

Por lo pronto tengo claro como crear, borrar, insertar, actualizar, moverme por la db... cosas muy simples pero que desconocía.

Lo que sí es seguro, es que hay que cambiar la forma de ver las cosas.

Para no hacer el post muy largo, continuaré en el siguiente,  creando una db de nuevo pero esta vez pensando en otro tipo de esquema para mis datos.

Nos vemos en el siguiente mongui!!:

Intentando crear un esquema para MongoDB