Node.js, MongoDB y redis – carrito de la compra

shoppingcart

En este tutorial vamos a ver como implementar un carrito de la compra. Para ello utilizaremos:

  • un servidor node.js con Express
  • una base de datos no-relacional de tipo clave-valor como es redis, para almacenar el carrito de forma termporal con tiempo de expiración y varias líneas de pedido (más info sobre redis)
  • una base de datos no relacional como es MongoDB para guardar el carrito una vez se realice la compra (más info sobre MongoDB) y mongoose

Partimos de una API RESTful que implementa los casos CRUD para una tienda de camisetas y que ya vimos en entradas anteriores. También podemos partir de la misma aplicación a la que añadimos el servicio “what’s hot now”

Lo que haremos será lo siguiente:

  • Crear un modelo carrito
  • Crear los servicios para:
    • añadir producto al carrito; el carrito se almacena en un hash en redis; en dicho hash habrá muchos productos (líneas de pedido); tiene tiempo de expiración de 5 minutos
    • ver el carrito; básicamente es ver los productos (líneas de pedido) que hay el el hash; las líneas de pedido tienen la id del producto y una cantidad
    • eliminar un producto del carrito; es eliminar una línea de pedido del hash
    • realizar compra; guarda el carrito con sus líneas de pedido en mongo
    • ver carritos que ya se hayan completado y estén en mongo

Las rutas serán las siguientes:

  • POST /addproduct – crea una línea de pedido
    • body: id (camiseta), amount (nº de unidades)
  • GET /seecart – muestra el carrito
  • DELETE /deleteproduct/:id – Borra una linea de pedido
    • id es el id del producto que se elimina
  • POST /closecart – Guarda el pedido en MongoDB
  • GET /listofclosedcarts – Muestra los pedidos cerrados

Para empezar, podéis descargar el código de la aplicación base desde github o el código de la aplicación base más el servicio “what’s hot now”. Además, debéis tener instalado Node.js, MongoDB  y redis. Una vez descargado el código, ejecutáis npm install para instalar todas las dependencias y npm install redis. Hecho esto, podéis arrancar MongoDB y el servidor node (node server.js) y crear las primeras camisetas. Podéis consultar más detalles en post anteriores.

Muy bien, empezamos. Lo primero es crear el modelo kart.js en la carpeta models.

Básicamente un carrito va a tener un ID del usuario que lo crea, una fecha de creación y un array de líneas de pedido, que se componen de un ID del producto y una cantidad.

A continuación, creamos el fichero karts.js en la carpeta routes. Dicho fichero va a tener lo siguiente:

Vamos a ir viendo uno a uno.

Primero comprobamos que el usuario mande en el cuerpo un ID y una cantidad (amount). A continuación comprobamos que el ID que ha enviado corresponde a una camiseta existente. Llegados a este punto metemos en un hash que tiene como clave key.44 el ID y el amount. Por último, ponemos un tiempo de expiración. Para guardar la línea de pedido en el hash utilizamos la función hmset(key, field, value).

Aclarar dos cosas. La primera, en este ejemplo siempre crearemos un carrito asociándolo a la clave  key.44; realmente debería ser key.IDusuario, pero como en este momento no tenemos usuarios registrados, suponemos que el usuario es el que tiene ID 44. Lo segundo es que cada vez que se añade un nuevo producto (línea de pedido) al carrito, el tiempo de expiración se actualiza y vuelve a ser de 5 minutos.

Lo siguiente que vamos a ver es la función seekart:

Aquí simplemente mostramos el hash de líneas de pedidos. Ver una vez más que tiene como clave key.44 debido al mismo motivo de antes. La función que utilizamos para obtener todos los valores del hash es hgetall(key).

Borrar una línea de producto del hash en redis en muy sencillo. Simplemente hay que utilizar la función hdel(key, field). Nosotros primero comprobaremos que exista la línea de pedido en el carrito; si existe, la borramos.

La siguiente función que vamos a ver es la de guardar el carrito en mongo.

Para ello, lo primero que hacemos es obtener todas las líneas de pedido del hash con el comando hgetall(key). Una vez más vemos que es key.44, pero seamos conscientes que debería ser key.IDusuario. A continuación verificamos que haya líneas de pedido en el hash, es decir, que no esté vacío. Si no está vació, metemos todas las líneas de pedido en un array y guardarmos en mongo con el comando save y pasando como user_id la ID del usuario (en este ejemplo es siempre 44) y el array de líneas de productos que tenemos almacenado en productsToKart.

Por último y muy sencillo, mostrar todos los carritos cerrados.

Una vez hecho esto, sólo nos quedaría añadir la siguiente línea al fichero server.js

Y con esto ya tienes un carrito efectivo con líneas de pedido en redis con tiempo de expiración y guardados los carritos comprados en MongoDB.

Vamos a probar que todo es correcto. Utilizaremos Postman en Google Chrome una vez más.

Primero accedemos a ver la lista de camisetas para poder copiar los ID y añadir productos al carrito con un ID correcto, puesto que sino no nos deja.

car1

A continuación vamos a añadir tres productos al carrito. Yo sólo pongo capturas de pantalla de dos.

car2 car3Veamos el contenido del carrito.

car4Y ahora vamos a borrar una línea de producto y a ver lo que ocurre cuando volvemos a mostrar el carrito.

car5

car6Veamos ahora como se cierra el pedido.

car7

 

Y ya por último vamos a ver la lista de carritos cerrados.

car8

Y esto ha sido todo! Espero que te resulte útil. Como siempre, puedes descargar el código desde GitHub.

Nota: En el código que te descargas desde GitHub, también hay implementado un servicio “what was hot”, que básicamente lo que hace es mantener en mongo un log con las camisetas a las que se ha accedido. Podemos consultar dicho log accediendo a GET /washot/:yearstart/:monthstart/:daystart/:yearend/:monthend/:dayend, de manera que se establece un filtrado de fechas con fecha de inicio y fecha de fin.

3 Responses to “Node.js, MongoDB y redis – carrito de la compra”

  1. Ezequiel dice:

    Hola Pablo,
    Desde ya muy interesantes tus posts, soy un iniciado en node.js y han sido de mucha utilidad, tengo una pregunta, el porqué de utilizar Redis, se que se pueden crear claves con expiración, pero quizas en el mismo MongoDB, otra collection, utilizando el atributo expires, algo similar a esto en un schema: new Schema({ createdAt: { type: Date, expires: 3600 }});
    o bien usando el modulo mongoose-ttl se podría llegar al mismo fin?
    Atento a tu respuesta desde ya, gracias!

  2. Faliorn dice:

    Igual me equivoco, pero la idea de usar Redis es precisamente NO ir a la base de datos a buscar la información. Se almacena la info en memoria RAM, lo cual acelera el acceso, de ahí el no usar otra colección en MongoDB.

    Un saludo

  3. Niravnnsb dice:

    Most help articles on the web are inaccurate or inheeorcnt. Not this!

Deja un comentario