Node.js: Persistiendo en Mongo
Actualmente estamos persistiendo la lista de noticias en un array guardado dentro de una variable global a nuestra instancia de node.js. Esta solución es solo temporal, necesitamos poder persistir la lista de noticias en algún medio persistente (que sobreviva al ciclo de vida de nuestro servidor node).
Vamos a usar MongoDB como base de datos. Mongo es una base de datos documental open-source.
Instalando MongoDB
Mongo correrá como un proceso separado de nuestro servidor node.js. Para instalarlo podemos seguir las siguientes instrucciones:
https://docs.mongodb.com/manual/administration/install-community/
Una vez instalado arrancaremos la base de datos ejecutando
$ mongod --dbpath mongo_data
Utilizando Mongoose
Mongoose es un cliente de mongodb que provee servicios de más alto nivel que los provistos por el driver original de mongo. Entre sus features podemos contar la capacidad de definir schemas para cada colección de objetos que tengamos en mongo (podemos ver a mongoose como un object-mapper entre objetos javascript y la estructura json que mongo persiste).
Utilizaremos npm
para instalar el modulo de mongoose.
$ npm install mongoose --save
Nos conectaremos a mongo por medio del siguiente código:
index.js
Una vez abierta la conexión con mongo deberemos proceder a configurar nuestro modelo por medio de uno o varios Schema. Un schema define la estructura que un objeto persistido en mongoose tendrá.
A continuación definimos schema y modelo para nuestro objeto noticia:
index.js
Desde este punto podemos modificar el código que teníamos para nuestras rutas de forma que utilice mongo (en lugar de una variable global) como medio persistente.
index.js
Asincronicidad
Post.find
es la función encargada de recuperar noticias desde mongo. Como muchas otras funciones en el ecosistema javascript/node.js funciona de forma asincrónica por lo que el flujo de control no se bloquea esperando que las noticias sean recuperadas desde mongo sino que continua. Una de las formas para poder hacer uso del resultado de la busqueda es especificar una función de callback la cuál será invocada con el mismo una vez que la operación asincrónica haya concluído. Dicha función de callback recibirá en este caso dos parametros:
err
- cuyo valor será distinto de null solamente si ocurrió algún error en la ejecución de la query.noticias
- con el resultado de la query
Para que la implementación de nuestras rutas esté completa deberíamos manejar de alguna forma el escenario en el cuál err
no es nulo. Una buena forma de hacerlo es propagando dicho error para que express pueda manejarlo eventualmente de forma genérica (esto se hace utilizando la función next
que es provista a todas las rutas de express)
index.js
Si utilizamos curl para probar nuestras rutas notaremos que las noticias son persistidas apropiadamente en mongo. Para inspeccionar el contenido de mongo recomendamos Robomongo
GitHub
Como referencia dejamos el estado del proyecto en GitHub
Callbacks vs Promises
Una mejor forma de manejar la asincrónicidad es hacer uso de Promises. Una Promise es un objeto que representa el resultado de una computación futura. Las funciones de mongoose como find
o save
retornan Promise
.
Una Promise
entiende fundamentalmente dos mensajes: then
y catch
. Ambos mensajes reciben una función por parametro la cuál será invocada asincrónicamente cuando la Promise
se resuelva a un valor o cuando ocurra un error, respectivamente.
El código de las rutas anteriores, utilizando promises, se traduce a:
index.js
o su versión más compacta:
index.js
En el resto de tutorial preferiremos utilizar Promise
por sobre sus alternativas a base de callbacks.