Mostrando entradas con la etiqueta CRUD. Mostrar todas las entradas
Mostrando entradas con la etiqueta CRUD. Mostrar todas las entradas

miércoles, 10 de abril de 2013

Intentando crear un esquema de datos para MongoDB

Esta vez trataré de crear un esquema más 'a lo NoSQL' para ver como puedo abordar la tarea de pasar KomanderTPV (corriendo el típico XAMPP con Apache, PHP, MySQL...) a NODE.JS + MONGODB.

Aviso de que este post no es un tutorial. Son los pasos (o palos) que voy dando para adentrarme en el mundo de node y mongo. Si lo sigues paso a paso irás fallando como yo lo he hecho... pero al menos habrás probado.

La situación que me planteo es la siguiente:

Un restaurante dividido en zonas, cada zona con sus mesas.Necesito un historial de cada mesa con los artículos que vayan pidiendo los clientes, los cuales pueden elegir entre un menú de carne o pescado.

Más o menos estas son las colecciones que necesito:

articulos: id, nombre, familia
mesas: id, nombre, zona
historial: id, fecha, mesa, descrip ( linea, articulo, precio)

Al lío:


> use km
switched to db km

> db.articulos
km.articulos
> a = db.articulos
km.articulos
> a.find();
> a.insert({_id:1, nombre: 'Churrasco', familia: 'Carnes'});


> a.insert({_id:2, nombre: 'Kobe', familia: 'Carnes'});
> a.insert({_id:3, nombre: 'Solomillo de Ternera', familia: 'Carnes'});
> a.insert({_id:4, nombre: 'Dorada', familia: 'Pescado'});
> a.insert({_id:5, nombre: 'Urta', familia: 'Pescado'});


Ya tengo mi colección 'articulos' con varios documentos.

Ahora las mesas:


> var m = db.mesas
> m.insert({_id:1, nombre:'1', zona:'Salon'});
> m.insert({_id:2, nombre:'2', zona:'Salon'});
> m.insert({_id:3, nombre:'3', zona:'Salon'});
> m.insert({_id:4, nombre:'4', zona:'Terraza'});
> m.insert({_id:5, nombre:'5', zona:'Terraza'});
> m.insert({_id:6, nombre:'6', zona:'Terraza'});

Veamos lo que he introducido hasta ahora:


> a.find();
{ "_id" : 1, "nombre" : "Churrasco", "familia" : "Carnes" }
{ "_id" : 2, "nombre" : "Kobe", "familia" : "Carnes" }
{ "_id" : 3, "nombre" : "Solomillo de Ternera", "familia" : "Carnes" }
{ "_id" : 4, "nombre" : "Dorada", "familia" : "Pescado" }
{ "_id" : 5, "nombre" : "Urta", "familia" : "Pescado" }
> m.find();
{ "_id" : 1, "nombre" : "1", "zona" : "Salon" }
{ "_id" : 2, "nombre" : "2", "zona" : "Salon" }
{ "_id" : 3, "nombre" : "3", "zona" : "Salon" }
{ "_id" : 4, "nombre" : "4", "zona" : "Terraza" }
{ "_id" : 5, "nombre" : "5", "zona" : "Terraza" }
{ "_id" : 6, "nombre" : "6", "zona" : "Terraza" }

El turno de la colección 'historial', donde se guardaran los pedidos realizados y sus mesas correspondientes. Pero esta colección se creará sobre la marcha. Así que solo la asignaremos a una variable para que sea más cómodo acceder a ella:

> var h = db.historial;

Reconstruyamos lo que pasaría paso por paso.

- El camarero lleva a sus clientes a la mesa 5. Lo primero que tiene que hacer es visualizar las mesas que hay en la zona 'Terraza' para poder visualizar la mesa que necesita:

> m.find({zona: 'Terraza'});
{ "_id" : 4, "nombre" : "4", "zona" : "Terraza" }
{ "_id" : 5, "nombre" : "5", "zona" : "Terraza" }
{ "_id" : 6, "nombre" : "6", "zona" : "Terraza" }


- El camarero pincha en la mesa 5 y se abre una nueva cuenta:

> h.insert({_id:1, fecha:new Date(2013,4,10), mesa:'5'});


- El camarero, muy amablemente, le canta el menú a sus clientes. Uno de ellos quiere un Churrasco. Al pulsar sobre churrasco, tendría que añadirse a la lista de pedidos:

Al definir la colección 'articulos' se me pasó añadir una clave 'precio'. Necesito crear el campo 'precio' en 'articulos`' (los pondré todos al mismo precio):

>a.update({},{'$set':{precio:8.60}}, false, true);

Ahora intentaré recuperar el valor 'precio' del articulo 'Churrasco' y meterlo en la nueva linea de descripción:

> var pvp=a.find({nombre:'Churrasco'}, {precio:1});
> h.update({_id:1},{'$set': {descrip:[{linea: 1, articulo: 'Churrasco', precio: pvp}]}});

Algo de lo que acabo de hacer está mal... si hago un find() en 'historial':


> h.find();
{ "_id" : 1, "descrip" : [      {       "linea" : 1,    "articulo" : "Churrasco"
,       "precio" : {    "_mongo" : {    "slaveOk" : false,      "host" : "127.0.
0.1" },         "_db" : {       "_mongo" : {    "slaveOk" : false,      "host" :
 "127.0.0.1" },         "_name" : "km" },       "_collection" : {       "_mongo"
 : {    "slaveOk" : false,      "host" : "127.0.0.1" },         "_db" : {
"_mongo" : {    "slaveOk" : false,      "host" : "127.0.0.1" },         "_name"
: "km" },       "_shortName" : "articulos",     "_fullName" : "km.articulos",
"_lastID" : 5 },        "_ns" : "km.articulos",         "_query" : {    "nombre"
 : "Churrasco" },       "_fields" : {   "precio" : 1 },         "_limit" : 0,
"_skip" : 0,    "_batchSize" : 0,       "_options" : 0,         "_cursor" : null
,       "_numReturned" : 0,     "_special" : false } } ], "fecha" : ISODate("201
3-05-09T22:00:00Z"), "mesa" : "5" }


Supongo que ha sido al coger el pvp... lo compruebo paso a paso:

Borro los documentos de la coleccion 'historial':

>db.historial.remove();
> h.find();

Inserto un historial nuevo:


> h.insert({_id:1, fecha:new Date(2013,4,5,17,25), mesa:'5'});
> h.find();
{ "_id" : 1, "fecha" : ISODate("2013-05-05T15:25:00Z"), "mesa" : "5" }

La fecha es lo que hay que mirar, pero eso luego...

> h.update({_id:1},{'$set':{descrip:[{linea:1, articulo:'Churrasco', precio: 8.60}]}});



Si ahora hago un find():


> h.find();
{ "_id" : 1, "descrip" : [ { "linea" : 1, "articulo" : "Churrasco", "precio" : 8
.6 } ], "fecha" : ISODate("2013-05-05T15:25:00Z"), "mesa" : "5" }
>

Sí, lo muestra bien... No habré pasado la variable correctamente... Puede que no lo haya pasado de la forma correcta... Añadiré una segunda línea con el operador $push:



> var pvp=a.find({nombre:'Churrasco'}, {precio:1});
> h.update({_id:1},{'$push':{descrip:[{linea:2, articulo:'Churrasco', precio: pvp.precio}]}});

Nada. El valor de precio lo pone a null...



{ "_id" : 1, "descrip" :
 [{"linea" : 1,"articulo" : "Churrasco","precio" : 8.6 }
,[{"linea" : 2,"articulo" : "Churrasco","precio" : null } ] ]
, "fecha" : ISODate("2013-05-05T15:25:00Z"), "mesa" : "5" }

Veamos que es lo que vale 'pvp':


> pvp
{ "_id" : 1, "precio" : 8.6 }


El _id no lo necesito para nada, ya que lo que usaré será el precio nada más:

> pvp=a.find({nombre:'Churrasco'}, {precio:1, _id:0});
{ "precio" : 8.6 }


pvp no contiene el valor de precio, sino un cursor... si usamos .hasNext() podemos ver si tiene elementos:


> var pvp=db.articulos.find({nombre:'Churrasco'}, {precio:1, _id:0});
> pvp.hasNext();
true


Si lo mostramos:


> print(pvp);
DBQuery: km.articulos -> { "nombre" : "Churrasco" }




> print(pvp.next().precio);
8.6

Ahora sí. Con .next() avanzamos una posición en el resultado devuelto por find(). Para recorrer una serie de documentos, es decir, el resultado de un find, usaremos:

> while(variable.hasNext()){printjson(variable.next().nombreclave)};


> var arts = db.articulos.find({familia:'Carnes'});
> while(arts.hasNext()){printjson(arts.next().nombre)};
"Churrasco"
"Kobe"
"Solomillo de Ternera"


o bien:

> variable.forEach(printjson)


> var arts = db.articulos.find({familia:'Carnes'});
> arts.forEach(printjson);
{ "_id" : 1, "familia" : "Carnes", "nombre" : "Churrasco", "precio" : 8.6 }
{ "_id" : 2, "familia" : "Carnes", "nombre" : "Kobe", "precio" : 8.6 }
{
        "_id" : 3,
        "familia" : "Carnes",
        "nombre" : "Solomillo de Ternera",
        "precio" : 8.6
}





Con todo esto, si quisiera agregar una nueva linea al pedido, pero esta vez usando el precio del articulo en una variable, hasta donde llego lo haría así:


> var pvp=a.find({nombre:'Churrasco'}, {precio:1});
> h.update({_id:1},{'$push':{descrip:[{linea:2, articulo:'Churrasco', precio: pv
p.next().precio}]}});

Lo compruebo:

> h.find().pretty();
{
        "_id" : 1,
        "descrip" : [
                {
                        "linea" : 1,
                        "articulo" : "Churrasco",
                        "precio" : null
                },
                [
                        {
                                "linea" : 2,
                                "articulo" : "Churrasco",
                                "precio" : null
                        }
                ],
                [
                        {
                                "linea" : 2,
                                "articulo" : "Churrasco",
                                "precio" : 8.6
                        }
                ]
        ],
        "fecha" : ISODate("2013-05-05T15:25:00Z"),
        "mesa" : "5"
}




Ok. Me ha insertado el precio del churrasco pero:

1.Me he equivocado y he añadido una nueva descrip con el mismo numero de linea.
2.Veo muchos corchetes en el resultado... suponía que sólo debo verlos una vez dentro de 'descrip'.


Primero revisaré la estructura. Para comprobar si estoy en lo correcto: Crearé un nuevo documento en 'historial', insertando dos lineas 'descrip' para ver si todo queda dentro de los corchetes:

> h.insert({_id:2, fecha: new Date(2013/04/10), mesa:'4', descrip:[{linea:1, art
iculo:'Churrasco', precio: 8.6},{linea:2, articulo:'Kobe', precio:8.6}]});



> h.find({_id:2}).pretty();
{
        "_id" : 2,
        "fecha" : ISODate("1970-01-01T00:00:00.050Z"),
        "mesa" : "4",
        "descrip" : [
                {
                        "linea" : 1,
                        "articulo" : "Churrasco",
                        "precio" : 8.6
                },
                {
                        "linea" : 2,
                        "articulo" : "Kobe",
                        "precio" : 8.6
                }
        ]


Este resultado me cuadra más (la fecha evidentemente no, pero he probado a introducirla de otra forma y ha salido esa). Seguramente me habré equivocado al hacer el $set o el $push... así que a probarlo de nuevo, a ver si al actualizar sigue todo dentro del mismo array 'descrip':


> h.insert({_id:3, fecha: new Date(), mesa:'4'});
> h.update({_id:3},{'$push':{descrip:{linea:1, articulo:'Churrasco', precio:8.6}}});


> h.update({_id:3},{'$push':{descrip:{linea:2, articulo:'Kobe', precio:8.6}}});

Lo compruebo:

> h.find({_id:3}).pretty();
{
        "_id" : 3,
        "descrip" : [
                {
                        "linea" : 1,
                        "articulo" : "Churrasco",
                        "precio" : 8.6
                },
                {
                        "linea" : 2,
                        "articulo" : "Kobe",
                        "precio" : 8.6
                }
        ],
        "fecha" : ISODate("2013-04-10T18:27:15.796Z"),
        "mesa" : "4"
}


Ahora sí me cuadra... Me cuadra hasta la fecha. Las líneas de 'descrip' están entre llaves, NO entre corchetes como aparecían al principio.

Lo único que no cuadra es el primer documento, ya que aparecen las lineas de descripción entre corchetes.
Así que lo borro y listo. Podía haber tratado de modificarlo, pero por hoy ya he tenido suficiente. Así que mañana será otro día y trataré de avanzar un poco más sobre el tema.