Buscadores, SEM SEO: el desafío de ser visto en la web
Nodejs Mongodb CRUD: Crea, lee, actualiza y elimina datos con Nodejs y Mongodb
1. Nodejs Mongodb CRUD (Desarrollo y Despliegue)
En este ejemplo práctico aprenderemos como crear una aplicación CRUD
(Create, Read, Update, Delete) de Nodejs y Mongodb adicionalmente de
algunos módulos o paquetes de Nodejs como Express, Handlebars, Babel,
Mongoose, dotenv, y otros que nos permitirán crear una aplicación que
administra tareas. Basado en un video de Fazt Code, noviembre de 2021.
Vamos a crear una aplicación de gestión de tareas
Consta de dos ventanas, una en la que escribimos la tarea, y otra que
estarán las tareas. En la primera tenemos dos campos con el botón añadir.
En el cuadro de lista de tareas, tenemos tres operaciones: pendiente
(pendiente), Delete (borrar) y editar (modificar). Si pulsamos pendiente
cambiará a hecho (hecho) y sin pulsamos editar, nos saldrá otra ventana
para editar esa tarea.
2. CONFIGURACION DEL PROYECTO.
Creamos carpeta e iniciamos proyecto
Instalamos dependencias
Express para crear servidor y las rutas, Handlebars como motor de
plantilla, Mongoose para modelar y manejar Mongodb, Morgan para ver las
peticiones http en consola y @babel/runtime para ejecutar los módulos de
babel.
3. Creamos la carpeta src, donde ira todo el código fuente. Dentro de esta
carpeta creamos el index.js.
Instalamos las dependencias de desarrollo.
Babel es una herramienta que nos permite transformar nuestro código JS
de última generación (o con funcionalidades extras) a un código de
JavaScript que cualquier navegador o versión de Node.
@babel/plugin-transform-runtime permite la reutilización del código
auxiliar inyectado de Babel.
Creamos el fichero de configuración de babel.
Empezamos con el fichero index.js
4. Ya podemos utilizar un JavaScript más avanzado.
Creamos el servidor.
Si lo ejecutamos:
Nos da un error, Node Js sigue sin reconocer import, para resolver este
problema debemos escribir:
5. El comando npx es una herramiena CLI que nos permite ejecutar paquetes
node desde la consola adjuntándole argumentos.
Creamos un script para evitar tener que escribir el comando de forma
seguida, además incorporando nodemon.
Utilizamos dev en vez de start para indicarle a node que estamos en etapa
de desarrollo. Para ejecutarlo:
Por último mostraremos un hola mundo en el navegador.
6. Creamos la carpeta routes para ir guardando todas las rutas.
Creamos un archivo index.routes.js y colocamos dentro, esta ruta.
El motivo de escribir de esta manera los ficheros es, para tenerlos mejor
diferenciados, ya que tenemos ya un fichero llamado index.js. Si nos fijamos
necesitamos el objeto app el cual, ya no está en este fichero, es decir
tenemos que traerlo. Para ello vamos a utilizar la función Router de Express,
que sirve para separar y diferenciar las distintas rutas.
7. Ahora vamos al fichero index.js e importamos todo esto.
Aunque a simple vista todo lo que hemos hecho parece más tedioso, es la
forma correcta y ordenada para crear una aplicación.
8. Pero si nos fijamos en el fichero index.js, tenemos mezclado código de
arrancar y de ejecutar la aplicación, separémosla. Creamos el fichero app.js
y movemos esta parte del código.
Y lo importamos desde el index.js.
HANDLEBARS
Es un motor de plantilla, para tener separador el html y javascript.
Creamos una carpeta llamada views dentro de src, que es donde iran todas
nuestras vistas o plantillas
Importamos engine de express-handlebars y el módulo path para configurar
la ruta multiplataforma.
9. Ahora le marcamos la ruta, la extensión y el motor de plantilla.
Por defecto el fichero que contendrá el diseño predeterminado se llama
main.hbs, y el directorio en el estará dicho fichero es el directorio layouts.
Vamos a crearlo además de otros dos ficheros llamado index.hbs y edit.hbs.
Vamos a escribir en ellos para ver que todo va funcionando
12. Si nos fijamos en las dos rutas conserva el navbar pero, cambia el contenido
de body ({{{body}}}).
MONGODB
Obviamente tenemos que tener instalado Mongodb. Para conectarnos a
Mongodb creamos el fichero database.js en el directorio raíz.
En ella importamos connect de Mongoose y creamos una función anónima
asíncrona en la que nos conectamos a nuestra BD (si no existe la crea
automáticamente), informándonos por consola.
Ahora solo nos queda importarlo desde index.js.
13. MONGOOSE
Con Mongoose lo que hacemos es modelar nuestra base de datos. Creamos la
carpeta models y dentro de esta el fichero Task.js.
Importamos Schema y model, para crear los campos y el modelo
respectivamente.
Luego creamos un nuevo esquema, y usamos timestamps que es una opción de
moongose para crear y actualizar los registros. Por ultimo exportamos el
modelo.
Ahora vamos a ponerles condiciones a los campos.
14. EL METODO POST
Vamos a crear una inteface para poder manipular estos datos.
Empezamos por crear un formulario en el fichero index.hbs.
El atributo action indica la ubicación del programa que procesará la
información enviada el navegador a través del método POST. Este programa
que está al lado del servidor está preparado para recibir y procesar los
datos del formulario.
15. Es el momento de poner a funcionar a Morgan. Con Morgan podemos ver
todas las peticiones http por consola.
Ahora si refrescamos la página http://localhost:3000/ nos saldrá por
consola que es un método GET, el código 304 y el tiempo de respuesta. Este
código indica que la petición a la URL no ha sido modificada desde que fue
requerida por última vez. Códigos http.
16. Si pulsamos el botón Añadir que recordemos tiene un método POST hacia
una ruta y un programa, nos dará la siguiente respuesta.
El código 404 nos informa que no se ha encontrado dicho recurso. Vamos a
resolverlo.
Con esto conseguimos mostrar un mensaje en el navegador y devolvernos por
consola el método utilizado y el código http 200, que significa petición ok.
Pero claro necesitamos los datos que escribimos en el formulario.
17. Para poder verlas por consola como un objeto json, primero colocamos el
middleware urlencoded en app.js.
Y le hacemos la petición en la ruta.
Esto significa que estamos recibiendo un objeto json, Lo que vamos hacer
es coger este objeto es guardarlo y verlo en el navegador. Primero
importamos el modelo.
18. Y a esta función (el modelo = Task) le pasamos el req.body.
Y mostrándola en consola.
Ya tenemos un objeto con su id generado automáticamente. Ahora vamos a
guardarlo en la BD.
GUARDANDO DATOS
Lo haremos de forma asíncrona.
En la línea 12 usamos el método save y se lo aplicamos al objeto tasks que ya
contiene el modelo con los datos del req.body, se lo pasamos a una constante
y lo mostramos por consola. Ya lo tenemos grabado en la BD. Vamos a
probarlo.
Escribimos los siguientes datos en el navegador y pulsamos añadir.
19. En el navegador veríamos guardado.
Y en la consola el objeto.
Además le ha añadido dos propiedades más: createdAt y updateAt. Esto es
gracia a la propiedad timestamps que añadimos en el model.
Viendo ya estos datos por consola sabemos que se ha guardado dentro de
MongoDB. Pero vamos a comprobarlo de dos formas más.
20. La primera de ella es a través de la consola de MongoDB. Escribiendo mongo
entramos al indicador.
Con el comando show dbs vemos todas las BBDD que tenemos en MongoDB.
Vemos que tenemos creada la nuestra, crud-mongo. Ahora con use
conmutamos en ella.
Vemos las colecciones que hay en la BBDD.
Cuando nosotros creamos un modelo en moongose,
21. Y nosotros guardamos datos dentro de ellos, MongoDB lo guarda como una
colección y le añade una s al final. Si queremos ver todos los campos que
tiene esa colección:
Y si queremos verlo de una forma más ordenada
La otra forma de verlo que está guardado en MongoDB es con virtual studio
code. Instalamos MongoDB for VS Code.
Ahora en la barra lateral saldrá el icono de MongoDB.
22. La pulsamos y nos saldrá lo siguiente:
La pulsamos y elegimos open form
Nos conectamos a localhost:27017
23. Ya podemos ver el documento en visual.
Bueno ya tenemos los datos guardados en la BBDD, vamos a cambiar en el
navegador el mensaje de guardado que nos muestra y lo vamos a re
direccionar a la página de inicio. Quitamos los console.log, al estar todo ok.
24. LISTAR TAREAS
Una vez guardados los datos en MongoDB, vamos a mostrar los datos en el
navegador.
En el fichero index.routers.js vamos a utilizar el método find(), que en
MongoDB y moongose sirve para listar todos los objetos de la BBDD. Ya lo
hemos usado antes desde la consola de MongoDB.
De esta forma lo vemos en consola.
25. Ahora vamos a ver como pasarlo al navegador.
De esta forma devolvemos un objeto con las propiedades de tasks.
En el fichero index.hbs debajo del formulario ya podemos invocar las
tareas.
26. Vamos a mostrarlos en una interface. Vamos a utiliza un bucle con el
comando each de handlerbars, que nos sirve para recorrer un listado.
Refrescamos el navegador.
Nos muestra el listado de los objetos. Pero nuestro es que se muestren con
formato, es decir el título separado del id etc.. Si nosotros le añadimos que
solo nos muestre los títulos:
Si refrescamos la página.
27. Nos saldrá vacia. Esto es motivado a que cuando nosotros le mandamos el
arreglo tasks,
Es un arreglo de MongoDB, no es un arreglo de JavaScript como tal. Esto se
arregla añadiendo lean() al comando find().
Consulta documentación.
Refrescamos página y ya, lo tenemos solucionado.
29. A la vez que estamos avanzando el código se va volviendo más tedioso y
nuestro fichero index.hbs más ilegible. Vamos a utilizar los partials
(parches) para ir dividiendo.
Creamos los archivos llamados taskForm.hbs y taskTable.hbs dentro de la
ruta partialstasks
El formulario irá a taskForm.hbs
Y la lista a taskTable.hbs
Y en el archivo index.hbs invocamos a estos dos archivos.
30. Como lo que nos muestra es una lista y nosotros lo que queremos es una
tabla, vamos a modificar el fichero taskTable.hbs.
Solo resaltar que @index es el indexado que sacamos de tasks. Aunque se
visualiza el resultado, nos falta darle formato.
31. ACTUALIZAR UNA TAREA
Vamos a convertir los botones de operaciones en enlaces, luego le daremos
formatos para que luzcan como botones. Nos resultará más fácil para las
peticiones GET.
Esto nos redirecciona al fichero edit.hbs. Vamos a construir un formulario
dentro.
Al formulario le asignamos la ruta edit pero con el método POST. Vamos a
crearla, y de momento solo nos enviará un mensaje.
32. Igual que en el anterior método POST vamos a ponerle un req.body.
Ahora nos vamos a la página principal y pulsamos editar a algunas de las
tareas.
Ahora nos sale la siguiente pantalla
El programa no sabe de qué objeto se trata. Para ello vamos a echar mano
del id.
33. Primero vamos a modificar las dos peticiones añadiéndole el id.
En la petición GET creamos la constante task y le pasamos el objeto que
contiene el id que viene en la ruta. Como es un objeto de MongoDB, le
colocamos .lean para convertirlo objeto JavaScript.
Y ahora le pasamos al render la propiedad task el objeto task.
Se puede simplificar.
Por ultimo vamos a colocarle el async.
34. Ahora pasamos los datos al formulario.
Y le pasamos el id al botón (enlace) editar.
Si pulsamos editar en algunas de las tareas ya la pinta en la ruta edit.
Al pulsar actualizar nos mandara al método POST. Este a su vez lleva el id
en la ruta.
35. Para que se guarde usaremos el método de Mongoose findByIdAndUpdate y
lo re direccionamos.
METODO DELETE
Vamos a cambiar el botón por el enlace.
Ahora creamos la ruta y el método delete.
Si pulsamos borrar
36. El registro se borra y nos re direcciona a la página principal.
CAMBIAR EL ESTADO DE TAREAS
Cuando creamos una tarea y pasa a la lista de tareas, el botón estará en
rojo y mostrará pendiente.
37. Si la pulsamos, el estado pasará a verdadero (true) y el botón se volverá
verde con una leyenda que diga hecho.
Provisionalmente, vamos a crear un enlace a una ruta y suprimimos el botón
Ahora vamos a nuestro enrutador (index.routes) y creamos la ruta.
En la línea 30 extraemos el id, en la 31 creamos una variable con ese
registro, en la 32 usamos el signo ! para cambiar de false a true y viceversa.
En la siguiente línea lo guardamos y luego lo re direccionamos.
Vamos a cambiar la interface para que muestre hecho o pendiente. Para ello
creamos un condicional.
38. Ahora si pulsamos en alguna tarea pendiente, por ejemplo a la 2
Pasará el estado a ‘hecho’.
CONTROLLERS
Vamos a separar las funciones de las rutas, es decir sacar fuera los
controladores para seguir el patrón de MVC (modelo vista controlador).
Creamos una carpeta controllers y dentro de esta el fichero
tasks.controller.js el cual, contendrán las funciones que tenemos con las
rutas.
39. Cortamos toda esta función y la pegamos en el nuevo fichero.
Y le asignamos una constante y lo exportamos.
Ahora en el fichero index.router lo importamos.
Y a la ruta el elemento importado.
Como en el nuevo fichero tasks.controllers utiliza constantes definidas en el
fichero Tasks.js, donde definimos los modelos, la tenemos que importar.
40. Hacemos lo mismo con añadir tarea.
Y lo importamos.
Hacemos lo mismo con el resto.
En el index quedaría de esta manera.
41. En este fichero en la cabecera importábamos el modelo pero, en este
fichero ya es innecesario por lo cual lo borramos.
VARIABLES DE ENTORNO
Sirve para guardar variables como el puerto, la ruta de la base de datos,
claves etc.. en un archivo que no se subirá cuando subamos el proyecto a
github o heroku.
El fichero donde guardamos las variables es .env. Primero vamos a instalar el
módulo dotenv.
Creamos la variable para mongo db.
Ahora creamos el fichero de configuración de las variables de entorno, el
fichero config.js dentro de src.
42. Solo nos queda ir al fichero donde llamamos a la base de datos y cambiarlo.
Ahora lo vamos hacer con el puerto.
Si no existe la variable process.env.PORT definida se conectara al puerto
3000.
Modificamos el index.js
Si nosotros definimos PORT en el fichero .env.
Ahora se conectará al puerto 5000.
43. IMPORTANTE
Esta configuración que hacemos con las variables de entorno, es importante
hacerla cuando vayamos a desplegar el proyecto en Heroku ya que el puerto
si lo ponemos directamente dará error.
Cuando desarrollamos un proyecto con Git, este crea un fichero .gitignore
donde apuntamos los ficheros que no queremos que suba. Vamos a crearlo y
a decirle que ignore el fichero .env y el directorio node_modules.
Hasta aquí tenemos el proyecto creado entero. Pero la interface creada en
el navegador no luce nada bien, se ve horrible. Vamos a usar bootstrap para
darle formato y estética.
BOOTSTRAP
Vamos a colocar el cdn de bootstrap en el fichero main.hbs
Ya con solo colocarle el cdn cambia el aspecto de nuestra app.
44. Creamos un fichero para la barra de navegación.
Y colocamos este fichero en main.hbs
Ahora vamos a organizar la página principal en el index.hbs
Ahora luciría de esta manera.
45. Ahora vamos a formatear el formulario.
Vamos a colocar el formulario dentro de una caja, con padding, color de
fondo y color a las letras.
Ahora modificamos los input.
46. Por último el botón añadir.
Una vez terminado el cuadro, vamos a darle formato a la tabla.
Ahora los botones.
47. Como detalle final vamos a crear una condición para cuando no haya tareas.
No deberá salir el encabezado de la tabla y en su lugar un mensaje con un
texto de no hay tarea y una imagen.
Metemos toda la tabla en un if
Y en el caso de que tasks sea false, es decir no haya tareas mostrará el
mensaje.
Una vez que le añadas una tarea:
48. Desaparece el texto.
Ahora que tenemos la página principal vamos a la de edición.
Esta es apariencia que tenemos.
Metemos todo el formulario en un cuadro y le damos forma.
49. Y damos clase a los input.
Ahora corregiremos para que todo el formulario no ocupe toda la pantalla.
Tenemos que meter todo el contenido en un div container, en otro que
especifique en columna y como van a quedar las columnas.
Ya por último el botón.
50. Ya solo queda personalizar la app para ello nos falta los ficheros estáticos.
FICHEROS ESTATICOS
Todos los ficheros estáticos como los css, img irán dentro de una carpeta
llamada public en el directorio principal (src), además tenemos que indicarle
la ruta en app.js.
Creamos el fichero css del main.hbs
Y se lo añadimos al fichero.
51. En el fichero main.css vamos configurando el estilo que le vamos a dar a la
página, en este ejercicio no vamos a profundizar el estilo, lo dejaremos para
otro momento, pero ya tenemos configurado el directorio public.
PRODUCCION
Vamos a crear un script para producción, de tal forma que el código lo pueda
interpretar los módulos de Node.
De esta forma crea un directorio llamado dist con JavaScript “antiguo” que
lo pueda leer todo los módulos y navegadores. Pero claro babel solo compila
JavaScript y solo copia al directorio dist los ficheros js. El directorio views
y el directorio public no los copia. Vamos a instalar el módulo ncp que sirve
para copiar directorios.
Y terminamos de escribir build
Ahora ejecutamos dicho comando.
52. Podemos comprobar que todo funciona escribiendo
Por último incluimos esta carpeta en el fichero .gitignore
DESPLIEGUE DEL PROYECTO
Github. Vamos a subir el proyecto a Github pero con la aplicación de github
escritorio.
Ahora nos vamos a mongo atlas.
Creamos un nuevo proyecto.
55. Copiamos la URI que ha generado y nos vamos a Heroku.
Heroku. Vamos a desplegar el proyecto en Heroku.
Seleccionamos setting
56. Y elegimos Reveal Config Vars
Creamos la variable de entorno y pegamos la uri que genero a mongo atlas y
cambiamos donde pone password por el password que pusimos al crear el
usuario.
Seguimos las instrucciones
57. Terminamos las instrucciones solo teniendo en cuenta que a veces en vez de
ser master es main.
Para ver el resultado pulsamos open app
58. Y en nuestro navegador tendremos:
Github.
Otro proyecto parecido.