Diferencia entre revisiones de «Node.js y MongoDB»

De Manuais Informática - IES San Clemente.
Ir a la navegación Ir a la búsqueda
(Ejecución asíncrona sin bloqueo)
(Creación de un servidor web en Nodejs)
 
(No se muestran 23 ediciones intermedias del mismo usuario)
Línea 97: Línea 97:
  
 
Otra buena alternativa puede ser el lenguaje [http://www.erlang.org/ Erlang] el cuál permite crear sistemas en tiempo real con alta escalabilidad y alta disponibilidad.
 
Otra buena alternativa puede ser el lenguaje [http://www.erlang.org/ Erlang] el cuál permite crear sistemas en tiempo real con alta escalabilidad y alta disponibilidad.
 +
 +
=== ¿Cuándo usar Node? ===
 +
 +
Node.js es muy adecuado para aplicaciones que se espera que vayan a gestionar una gran cantidad de conexiones concurrentes. Además, debe tenerse en cuenta que es más adecuado para aplicaciones donde cada solicitud entrante requiere muy poca CPU o ciclos. Esto significa que si tiene la intención de realizar tareas de computación intensivas en las solicitudes, terminará bloqueando el bucle de eventos, lo que afectará otras solicitudes que se soliciten al servidor web.
 +
 +
Node.js es muy adecuado para aplicaciones web en tiempo real, como salas de chat, herramientas de colaboración, juegos en línea, etc. Entonces para decidir si usar o no usar Node.js, debemos analizar el contexto de la aplicación en serio y descubrir si Node.js realmente se adapta al contexto de la aplicación.
  
 
= Instalacion de Node.js y npm (node packet manager) en Debian =
 
= Instalacion de Node.js y npm (node packet manager) en Debian =
Línea 160: Línea 166:
  
 
{{#ev:youtube|sgiNp1EQsIM}}
 
{{#ev:youtube|sgiNp1EQsIM}}
 +
 +
= El sistema de módulos en NodeJs =
 +
 +
En un esfuerzo por hacer que el código sea lo más modular y reutilizable posible, Node utiliza un sistema de módulos que le permite organizar mejor su código. La idea básica es escribir un código que soluciona un problema y se exporta como un módulo.
 +
 +
Luego, cada vez que necesite usar ese código en otro lugar en su código, lo cargaremos y lo usaremos, ejemplo:
 +
<source lang="javascript">
 +
 +
// ** archivo: sumas.js
 +
module.exports = {
 +
  sumar: function (param1, param2) {
 +
    return param1 + param2;
 +
  }
 +
}
 +
 +
// ** archivo: pruebas.js
 +
 +
var mimodulo = require ('./sumas'); // nota: fijarse que no lleva la extensión .js en el archivo
 +
var algo = 1;
 +
var otracosa = 2;
 +
var nuevoValor= mimodulo.sumar (algo, otracosa);
 +
console.log (nuevoValor);
 +
// => 3
 +
 +
</source>
 +
 +
Con este sistema, es fácil reutilizar la funcionalidad de un módulo (en este caso, el módulo sumas) en otros archivos.
 +
 +
Además, los archivos individuales de un módulo actúan como un espacio de nombres privado. Cualquier variable declarada y utilizada dentro del archivo del módulo es privado para ese módulo y no está expuesto a ningún código que use el módulo a través de require ().
 +
 +
Este sistema también se extiende infinitamente. Dentro de unos módulos módulos, se pueden requerir otro módulos y así sucesivamente.
 +
 +
= El core de Node.js y los módulos =
 +
 +
El núcleo de Node.js literalmente tiene cientos de módulos disponibles a la hora de escribir aplicaciones.
 +
 +
Entre ellos tenemos los siguientes:
 +
* Events
 +
* HTTP
 +
* Filesystems
 +
* Net
 +
* Streams
 +
* Timers
 +
 +
Para instalar los módulos lo haremos utilizando npm (Node Package Manager):
 +
 +
Por ejemplo:
 +
<source lang="javascript">
 +
npm install express
 +
 +
// Luego podremos utilizarlo en un fichero -ks
 +
 +
var express = require ('express');
 +
 +
</source>
 +
 +
= MongoDB =
 +
 +
MongoDB es una base de datos escalable, de alto rendimiento, orientada a documentos y sin esquema predefinido.
 +
 +
MongoDB se aleja del clásico paradigma relacional. En este sentido, podemos llamarla una base de datos “NoSQL”, que es un término que se acuñó hace unos años para indicar que no se va a emplear SQL, ampliamente extendido en las bases de datos comerciales como Oracle, MySQL, MariaDB, SQL Server, etc.
 +
 +
Se trata de un sistema de bases de datos de código abierto y completamente gratuito, si bien la empresa que lo creó ofrece servicios profesionales a empresas.
 +
 +
 +
'''Y si no usa SQL, ¿qué utiliza en su lugar?'''
 +
 +
El sistema MongoDB está orientado a documentos.
 +
 +
Estos documentos se crean y consultan en formato JSON (Java Script Object Notation) y son fácilmente modificables y accesibles. Esto hace que sea una base de datos ideal para desarrollo ágil (agile development) y que permita a los desarrolladores hacer modificaciones rápidamente en su código.
 +
 +
Uno de los principales objetivos de los creadores de MongoDB era hacer una base de datos que permitiera a los desarrolladores interactuar con ella de la forma más sencilla posible.
 +
 +
 +
'''¿Es mejor o peor que una base de datos SQL?'''
 +
 +
Un sistema de bases de datos relacional (SQL) almacena los datos en tablas con filas y campos, mientras que MongoDB lo hace en colecciones de documentos JSON (aunque internamente trabaja con BSON (Binary JSON).
 +
 +
Los desarrolladores han sacrificado algunas de las características que ofrecen las bases de datos relacionales (transacciones, normalización), para acercarse a las necesidades de los desarrolladores de aplicaciones (flexibilidad, escalabilidad).
 +
 +
Existen drivers de conexión a MongoDB para la mayoría de los lenguajes de programación, sistemas de balanceo de carga, posibilidad de escalar horizontalmente, y una capacidad ilimitada de almacenamiento.
 +
 +
El tipo de licencia es GNU APGL, y funciona en Windows, Linux, OS X y Solaris, con lo cual tampoco nos dará un quebradero de cabeza a la hora de comprar la licencia como otras bases de datos comerciales, pues es totalmente gratuita.
 +
 +
== Instalación de MongoDB en Debian 10 ==
 +
 +
<source lang="bash">
 +
# Nos pasamos a root
 +
sudo su
 +
 +
# Importamos la clave GPG de MongoDB
 +
apt update
 +
apt -y install gnupg2
 +
wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | apt-key add -
 +
 +
# Añadimos el repositorio de MongoDB
 +
echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main" | tee /etc/apt/sources.list.d/mongodb-org.list
 +
 +
# Actualizamos los repositorios
 +
apt-get update
 +
 +
# Instalamos la última versión estable:
 +
apt-get install -y mongodb-org
 +
 +
# Para activar el servicio de MongoDB en el arranque:
 +
systemctl enable --now mongod
 +
 +
# Podemos comprobar el estado de MongoDB con:
 +
systemctl status mongod.service
 +
 +
# Obtendremos algo como:
 +
root@dwes:/home/veiga# systemctl status mongod.service
 +
● mongod.service - MongoDB Database Server
 +
  Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
 +
  Active: active (running) since Wed 2019-12-04 23:35:46 CET; 30s ago
 +
    Docs: https://docs.mongodb.org/manual
 +
Main PID: 13262 (mongod)
 +
  Memory: 105.0M
 +
  CGroup: /system.slice/mongod.service
 +
          └─13262 /usr/bin/mongod --config /etc/mongod.conf
 +
 +
Dec 04 23:35:46 dwes systemd[1]: Started MongoDB Database Server.
 +
 +
 +
# Para ver el puerto en el que está escuchando:
 +
ss -tunelp
 +
 +
# Y veremos que está escuchando en localhost (127.0.0.1) y en el puerto 27017
 +
 +
root@dwes:/home/veiga# ss -tunelp
 +
Netid  State  Recv-Q  Send-Q  Local Address:Port    Peer Address:Port
 +
udp    UNCONN  0      0              0.0.0.0:68          0.0.0.0:*    users:(("dhclient",pid=287,fd=7)) ino:10558 sk:1 <->
 +
tcp    LISTEN  0      20          127.0.0.1:25          0.0.0.0:*    users:(("exim4",pid=797,fd=3)) ino:13855 sk:2 <->
 +
tcp    LISTEN  0      128            0.0.0.0:443          0.0.0.0:*    users:(("nginx",pid=425,fd=9),("nginx",pid=424,fd=9)) ino:12197 sk:3 <->
 +
tcp    LISTEN  0      128          127.0.0.1:27017        0.0.0.0:*    users:(("mongod",pid=13262,fd=11)) uid:109 ino:68111 sk:4 <->
 +
tcp    LISTEN  0      80          127.0.0.1:3306        0.0.0.0:*    users:(("mysqld",pid=422,fd=22)) uid:107 ino:12319 sk:5 <->
 +
tcp    LISTEN  0      128            0.0.0.0:80          0.0.0.0:*    users:(("nginx",pid=425,fd=6),("nginx",pid=424,fd=6)) ino:12194 sk:6 <->
 +
tcp    LISTEN  0      128            0.0.0.0:22          0.0.0.0:*    users:(("sshd",pid=534,fd=3)) ino:13324 sk:7 <->
 +
tcp    LISTEN  0      128              [::]:443            [::]:*    users:(("nginx",pid=425,fd=8),("nginx",pid=424,fd=8)) ino:12196 sk:8 v6only:1 <->
 +
tcp    LISTEN  0      128              [::]:80              [::]:*    users:(("nginx",pid=425,fd=7),("nginx",pid=424,fd=7)) ino:12195 sk:9 v6only:1 <->
 +
tcp    LISTEN  0      128              [::]:22              [::]:*    users:(("sshd",pid=534,fd=4)) ino:13335 sk:a v6only:1 <->
 +
 +
# El puerto de escucha lo podríamos modificar editando el fichero /etc/mongod.conf:
 +
nano /etc/mongod.conf
 +
 +
# En la sección de network interfaces modificaremos los datos que queramos:
 +
 +
# network interfaces
 +
net:
 +
  port: 27017
 +
  bindIp: 127.0.0.1
 +
 +
# Una vez hechos los cambios reiniciamos con:
 +
systemctl restart mongod.service
 +
 +
 +
 +
 +
 +
 +
</source>
 +
 +
== El shell de MongoDB ==
 +
 +
Para acceder a MongoDB desde el shell haremos:
 +
 +
<source lang="bash">
 +
mongo
 +
 +
# Para salir teclearemos:
 +
exit
 +
 +
</source>
 +
 +
== Cómo configurar la autenticación en MongoDB ==
 +
 +
<source lang="bash">
 +
# Primero conectaremos a mongoDB
 +
mongo
 +
 +
# Si estuviera configurado para un puerto diferente, por ejemplo el 27017:
 +
mongo --port 27017
 +
 +
# Vamos a crear un usuario admin en la base de datos admin:
 +
# Nos conectamos a la base de datos admin:
 +
> use admin;
 +
 +
# Creamos el usuario:
 +
> db.createUser(
 +
  {
 +
    user: "admin",
 +
    pwd: "abc123.",
 +
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
 +
  }
 +
)
 +
> exit
 +
bye
 +
 +
 +
# Abrimos /etc/mongod.conf
 +
nano /etc/mongod.conf
 +
 +
# Habilitamos la autenticación
 +
 +
security:
 +
  authorization: enabled
 +
 +
# Reiniciamos el servicio:
 +
systemctl restart mongod
 +
 +
# Probamos a conectarnos a la base de datos testdb con el usuario dbadmin:
 +
mongo -u "dbadmin" -p "abc123." --authenticationDatabase "admin"
 +
 +
# El usuario administrador tiene permisos para crear y gestionar la base de datos de usuarios. Si queremos leer o escribir en la base de datos tendremos que crear un usuario adicional con permisos de lectura y escritura en la base de datos.
 +
 +
# Si queremos crear usuarios para una base de datos específica:
 +
 +
# Nos conectamos a la base de datos. Si no existe la creará automáticamente:
 +
use test
 +
 +
# Podemos usuar la funcion db.createUser() para crear un usuario para nuestra base de datos. La palabra clave db, hace referencia a la base de datos actual con la que estamos trabajando.
 +
 +
db.createUser(
 +
  {
 +
    user: "testUser",
 +
    pwd: "xyz123",
 +
    roles: [ { role: "readWrite", db: "test" } ]
 +
  }
 +
)
 +
 +
# Ahora podemos loguearnos en la base de datos "test" con el usuario testUser con permisos de lectura y escritura.
 +
mongo --port 27017 -u "testUser" -p "xyz123" --authenticationDatabase "test"
 +
 +
# Para ver la base de datos en la que estamos trabajando, teclear:
 +
db
 +
 +
</source>
 +
 +
== Insertando datos en MongoDB ==
 +
 +
== Insertando datos en MongoDB ==
 +
== Consultas en MongoDB ==
 +
== Actualizando datos en MongoDB ==
 +
== Borrando datos en MongoDB ==
 +
 +
 +
Una característica realmente poderosa de npm es que permite de una forma rápida, fácil y consistente que otros desarrolladores inicien su código en su entorno local. Los proyectos de Node normalmente incluyen un archivo especial llamado '''package.json''' que incluye información
 +
sobre el proyecto, así como una lista de todos los paquetes npm de los que depende el proyecto.
 +
 +
Un desarrollador con una copia de su código local puede simplemente ejecutar '''npm install''' para tener cada dependencia descargada e instalada localmente usando este archivo '''package.json'''.
 +
 +
El indicador de instalación de '''npm --save''' o '''--save-dev''' es obligatorio si se desea que la dependencia que se está instalando sea guardada como referencia dentro del archivo package.json. Si estás comenzando un nuevo proyecto y no desea crear un archivo package.json a mano, simplemente puede ejecutar '''npm init''' y responder a algunas preguntas rápidas para obtener un paquete predeterminado.json configurado rápidamente.
 +
 +
Puede dejar cada pregunta en blanco durante init y aceptar los valores predeterminados si se desea:
 +
<source lang="bash">
 +
$ npm init
 +
$ npm install express --save
 +
$ npm install grunt --save-dev
 +
$ cat package.json
 +
{
 +
"name": "chapter3",
 +
"version": "0.0.0",
 +
"description": "",
 +
"main": "index.js",
 +
"scripts": {
 +
  "test": "echo \"Error: no test specified\" && exit 1"
 +
},
 +
"author": "",
 +
"license": "ISC",
 +
"dependencies": {
 +
  "express": "^3.5.1"
 +
},
 +
"devDependencies": {
 +
  "grunt": "^0.4.4"
 +
}
 +
}
 +
 +
</source>
  
 
= Creación de un servidor web en Nodejs =
 
= Creación de un servidor web en Nodejs =
Línea 166: Línea 450:
  
 
Vamos a ver cómo crear un servidor web con Node y enviar contenido a través de él, con seguridad y eficiencia.
 
Vamos a ver cómo crear un servidor web con Node y enviar contenido a través de él, con seguridad y eficiencia.
 
== Ajustando las rutas ==
 
  
 
Para poder enviar contenido web necesitamos crear una URI (Universal Resource Identifier) que identifique el recurso al que queremos acceder. En otras palabras crear las diferentes rutas de la aplciación que mostrarán las diferentes páginas o contenidos de la web.
 
Para poder enviar contenido web necesitamos crear una URI (Universal Resource Identifier) que identifique el recurso al que queremos acceder. En otras palabras crear las diferentes rutas de la aplciación que mostrarán las diferentes páginas o contenidos de la web.
Línea 235: Línea 517:
 
</source>
 
</source>
  
== Sirviendo ficheros estáticos ==
+
 
== Cacheado de contenido en memoria para entrega inmediata ==
+
[[Usuario:Veiga|Veiga]] ([[Usuario discusión:Veiga|discusión]]) 00:30 5 dic 2019 (CET)
== Optimización ==
 

Revisión actual del 00:30 5 dic 2019

Node.js

Introducción a Node.js

Node.js es un entorno JavaScript de lado de servidor que utiliza un modelo asíncrono y dirigido por eventos.

Node usa el motor de JavaScript V8 de Google: una VM tremendamente rápida y de gran calidad escrita por gente como Lars Bak, uno de los mejores ingenieros del mundo especializados en VMs.

No olvidemos que V8 es actualizado constantemente y es uno de los intérpretes más rápidos que puedan existir en la actualidad para cualquier lenguaje dinámico. Además las capacidades de Node para I/O (Entrada/Salida) son realmente ligeras y potentes, dando al desarrollador la posibilidad de utilizar a tope la I/O del sistema. Node soporta protocolos TCP, DNS y HTTP.

Una de las cosas más importantes por las que la gente se confunde cuando se explica Node.js es entender qué es exactamente. ¿Es un lenguaje diferente? ¿es solo un framework por encima o es algo más?

Node.js definitivamente no es un nuevo lenguaje, y no es solo un framework de JavaScript. Puede ser considerado como un entorno de tiempo de ejecución para JavaScript construido sobre el motor V8 de Google.

Entonces, nos proporciona un contexto donde podemos escribir código JavaScript en cualquier plataforma donde se puede instalar Node.js. ¡En cualquier sitio!

Ahora un poco sobre su historia! En 2009, Ryan Dahl hizo una presentación en JSConf eso cambió JavaScript para siempre. Durante su presentación, presentó a Node.js La comunidad JavaScript. Después de una charla de aproximadamente 45 minutos, concluyó, recibiendo una gran ovación de la audiencia en el proceso. Se inspiró para escribir Node.js después de ver una barra de progreso de carga de archivos simple en Flickr, el sitio para compartir imágenes.

Al darse cuenta de que el sitio estaba realizando todo el proceso de manera incorrecta, él decidió que tenía que haber una mejor solución.

Ahora veamos las características de Node.js, que lo hace único de otros lenguajes de programación del lado del servidor.


La ventaja que aporta el motor V8 de Google

El motor V8 fue desarrollado por Google y fue de código abierto en 2008. JavaScript es un lenguaje interpretado y no será tan eficiente como un lenguaje compilado, ya que cada línea de código se interpreta una por una mientras el código se ejecuta.

El motor V8 trae un modelo eficiente aquí, donde el código de JavaScript se compilará en código de nivel de máquina y las ejecuciones sucederán en el código compilado en lugar de interpretar el JavaScript. Pero a pesar de que NodeJS está utilizando el motor V8, Joyent, que es la compañía que mantiene NodeJS, no siempre actualiza el motor V8 a las últimas versiones que Google lanza activamente. Esto ha llevado a la nueva variante llamada io.js.

Node.js mantiene un único subproceso

Tal vez se pregunte, ¿cómo ayuda un modelo de subproceso único?

Típicamente PHP, ASP.Los servidores NET, Ruby o basados ​​en Java siguen un modelo donde cada cliente solicita resultados con la instanciación de un nuevo hilo o incluso un proceso. Cuando se trata de Node.js, las solicitudes se ejecutan en el mismo hilo, incluso con recursos compartidos.

¿Cuál será la ventaja de usar ese modelo de hilo único?

Primero debemos entender el problema que Node.js intenta resolver. Intenta hacer procesamiento asíncrono en un solo hilo para proporcionar más rendimiento y escalabilidad para aplicaciones que supuestamente manejan demasiado tráfico web.

Imagine aplicaciones web que manejan millones de solicitudes concurrentes; si el servidor crea un nuevo hilo para manejar cada solicitud que llega, consumirá muchos recursos y terminaríamos intentando agregar más y más servidores para aumentar la escalabilidad de la aplicación. El modelo de procesamiento asíncrono de subproceso único, tiene su ventaja en el contexto anterior, y puede procesar muchas más solicitudes concurrentes con menos cantidad de recursos del lado del servidor. Sin embargo, hay un desventaja de este enfoque: el nodo (por defecto) no utilizará la cantidad de CPU cores disponibles en el servidor en el que se ejecuta, sin utilizar módulos adicionales como pm2.

Ejecución asíncrona sin bloqueo

Una de las características más poderosas de NodeJs es que está dirigido por eventos y asíncrono. Entonces, ¿cómo funciona un modelo asincrónico?

Imagina que tienes un bloque de código y en alguna enésima línea tiene una operación que requiere mucho tiempo.

Y qué sucede con las líneas que siguen a la enésima línea mientras se ejecuta este código? En modelos de programación síncrona, las líneas que siguen a la enésima línea tendrán que esperar hasta que se complete la operación en esa línea. Un modelo asincrónico maneja este caso de forma distinta. Para gestionar este escenario en un enfoque asincrónico, necesitamos segmentar el código que sigue a la enésima línea en dos secciones: la primera sección es dependiente del resultado de la operación en la enésima línea y la segunda sección es independiente del resultado.

Envolvemos el código dependiente en una función con el resultado de la operación como su parámetro y lo registramos como una función de retorno (callback) que se llamará cuando terminó con éxito la operación. Una vez la operación está completa, la función de devolución de llamada se activará con su resultado. Mientras tanto, podemos continuar ejecutando las líneas independientes del resultado sin esperar el resultado.

En este escenario, la ejecución nunca se bloquea para que se complete un proceso. Solo va con funciones de devolución de llamada registradas en cada finalización. En pocas palabras, usted asigna una función de devolución de llamada a una operación, y cuando NodeJS determina que ha finalizado la tarea, se activa el evento, y ejecutará su función de devolución de llamada en ese momento.

Para entenderlo veamos un ejemplo de asincronía en detalle:

console.log('Uno');
console.log('Dos');
setTimeout(function() {
   console.log('Tres');
}, 2000);
console.log('Cuatro');
console.log('Cinco');

# En una llamada típica síncrona el código anterior devolvería:

Uno
Dos
... (2 segundos de espera) ...
Tres
Cuatro
Cinco

# Sin embargo en una llamada asíncrona, el resultado sería:

Uno
Dos
Cuatro
Cinco
... (approx. 2 segundos de espera) ...
Tres

# La función que actualmente muestra "Tres" y que está asignada al TimeOut se denomina función de callback o retorno.

¿Qué diferencias tiene Node.js respecto a Apache u otros servidores web?

  • Apache crea un nuevo hilo por cada conexión cliente-servidor. Esto funciona bien para pocas conexiones, pero crear nuevos hilos tiene un coste, así como la realización de cambios de contexto. A partir de 400 conexiones simultáneas, el número de segundos para atender las peticiones crece considerablemente. Podemos decir que Apache funciona bien pero no es el mejor servidor para lograr máxima concurrencia (lograr tener el número mayor de conexiones abiertas posibles).
  • Uno de los puntos fuertes de Node es su capacidad de mantener muchas conexiones abiertas y esperando. En Apache por ejemplo el parámetro MaxClients por defecto es 256. Este valor puede ser aumentado para servir contenido estático, sin embargo si se sirven aplicaciones web dinámicas en PHP u otro lenguaje es probable que al poner un valor alto el servidor se quede bloqueado ante muchas conexiones -esto dependerá del trabajo que la aplicación web de al servidor y de su capacidad hardware-.
  • Una aplicación para Node se programa sobre un solo hilo. Si en la aplicación existe una operación bloqueante (entrada/salida por ejemplo), Node creará entonces otro hilo en segundo plano, pero no lo hará sistemáticamente por cada conexión como haría Apache.
  • En teoría Node puede mantener tantas conexiones como número máximo de archivos descriptores (sockets) soportados por el sistema. En un sistema UNIX este límite puede rondar por las 65.000 conexiones, un número muy alto. Sin embargo en la realidad la cifra depende de muchos factores, como la cantidad de información que esté la aplicación distribuyendo a los clientes.
  • Una aplicación con actividad normal podría mantener 20.000-25.000 clientes a la vez sin haber apenas retardo en las respuestas. Un inconveniente de Node es que debido a su arquitectura (de usar sólo un hilo) también sólo podrá usar una CPU. Un método para usar múltiples núcleos sería iniciar múltiples instancias de Node en el servidor y poner un balanceador de carga delante de ellos.

Node.js no es el único servidor de este tipo, hay otros proyectos como Tornado (Python), Twisted(Python),Apache Mina(Java), Jetty(Java), etc.

Otra buena alternativa puede ser el lenguaje Erlang el cuál permite crear sistemas en tiempo real con alta escalabilidad y alta disponibilidad.

¿Cuándo usar Node?

Node.js es muy adecuado para aplicaciones que se espera que vayan a gestionar una gran cantidad de conexiones concurrentes. Además, debe tenerse en cuenta que es más adecuado para aplicaciones donde cada solicitud entrante requiere muy poca CPU o ciclos. Esto significa que si tiene la intención de realizar tareas de computación intensivas en las solicitudes, terminará bloqueando el bucle de eventos, lo que afectará otras solicitudes que se soliciten al servidor web.

Node.js es muy adecuado para aplicaciones web en tiempo real, como salas de chat, herramientas de colaboración, juegos en línea, etc. Entonces para decidir si usar o no usar Node.js, debemos analizar el contexto de la aplicación en serio y descubrir si Node.js realmente se adapta al contexto de la aplicación.

Instalacion de Node.js y npm (node packet manager) en Debian

Veamos como realizar la instalación de Node.js y el gestor de paquetes de Node npm.

Instalación de Node.js en Debian

Para instalar la última versión de Nodejs haremos lo siguiente:

curl -sL https://deb.nodesource.com/setup_13.x | sudo bash -

# Instalamos a continuación nodejs y npm
apt-get install -y nodejs

# Chequeamos la versión instalada:
node -v

v13.2.0

Comandos básicos en el uso de Node.js

Desde la línea de comandos de node podemos teclear instrucciones para ejecutar aplicaciones o bien escribir una aplicación. En general lo que se suele hacer es crear un fichero .js con las instrucciones de la aplicación que va a ejecutar Node.

El entorno de trabajo al que se accede desde la línea de comandos se denomina REPL.

// Para acceder a la línea de comandos REPL de node:
node

// Accederemos a la consola de trabajo indicada con el símbolo >

// Para consultar ayuda de node:
> .help

// Para salir de node:
> .exit
// O bien CTRL+C CTRL+C

// Ejemplo de código de javascript en el entorno REPL de node:
>a=4;
4


// Ejemplo de pequeño programa en linea de comandos >:
> a=[1,2,3];
> a.forEach(function(valor){
..... console.log(valor);
..... });

// Producirá como resultado
1
2
3

Ejemplo de video con comandos de prueba en el entorno REPL de Node:

El sistema de módulos en NodeJs

En un esfuerzo por hacer que el código sea lo más modular y reutilizable posible, Node utiliza un sistema de módulos que le permite organizar mejor su código. La idea básica es escribir un código que soluciona un problema y se exporta como un módulo.

Luego, cada vez que necesite usar ese código en otro lugar en su código, lo cargaremos y lo usaremos, ejemplo:

// ** archivo: sumas.js
module.exports = {
  sumar: function (param1, param2) {
    return param1 + param2;
  }
}

// ** archivo: pruebas.js

var mimodulo = require ('./sumas'); // nota: fijarse que no lleva la extensión .js en el archivo
var algo = 1;
var otracosa = 2;
var nuevoValor= mimodulo.sumar (algo, otracosa);
console.log (nuevoValor);
// => 3

Con este sistema, es fácil reutilizar la funcionalidad de un módulo (en este caso, el módulo sumas) en otros archivos.

Además, los archivos individuales de un módulo actúan como un espacio de nombres privado. Cualquier variable declarada y utilizada dentro del archivo del módulo es privado para ese módulo y no está expuesto a ningún código que use el módulo a través de require ().

Este sistema también se extiende infinitamente. Dentro de unos módulos módulos, se pueden requerir otro módulos y así sucesivamente.

El core de Node.js y los módulos

El núcleo de Node.js literalmente tiene cientos de módulos disponibles a la hora de escribir aplicaciones.

Entre ellos tenemos los siguientes:

  • Events
  • HTTP
  • Filesystems
  • Net
  • Streams
  • Timers

Para instalar los módulos lo haremos utilizando npm (Node Package Manager):

Por ejemplo:

npm install express

// Luego podremos utilizarlo en un fichero -ks

var express = require ('express');

MongoDB

MongoDB es una base de datos escalable, de alto rendimiento, orientada a documentos y sin esquema predefinido.

MongoDB se aleja del clásico paradigma relacional. En este sentido, podemos llamarla una base de datos “NoSQL”, que es un término que se acuñó hace unos años para indicar que no se va a emplear SQL, ampliamente extendido en las bases de datos comerciales como Oracle, MySQL, MariaDB, SQL Server, etc.

Se trata de un sistema de bases de datos de código abierto y completamente gratuito, si bien la empresa que lo creó ofrece servicios profesionales a empresas.


Y si no usa SQL, ¿qué utiliza en su lugar?

El sistema MongoDB está orientado a documentos.

Estos documentos se crean y consultan en formato JSON (Java Script Object Notation) y son fácilmente modificables y accesibles. Esto hace que sea una base de datos ideal para desarrollo ágil (agile development) y que permita a los desarrolladores hacer modificaciones rápidamente en su código.

Uno de los principales objetivos de los creadores de MongoDB era hacer una base de datos que permitiera a los desarrolladores interactuar con ella de la forma más sencilla posible.


¿Es mejor o peor que una base de datos SQL?

Un sistema de bases de datos relacional (SQL) almacena los datos en tablas con filas y campos, mientras que MongoDB lo hace en colecciones de documentos JSON (aunque internamente trabaja con BSON (Binary JSON).

Los desarrolladores han sacrificado algunas de las características que ofrecen las bases de datos relacionales (transacciones, normalización), para acercarse a las necesidades de los desarrolladores de aplicaciones (flexibilidad, escalabilidad).

Existen drivers de conexión a MongoDB para la mayoría de los lenguajes de programación, sistemas de balanceo de carga, posibilidad de escalar horizontalmente, y una capacidad ilimitada de almacenamiento.

El tipo de licencia es GNU APGL, y funciona en Windows, Linux, OS X y Solaris, con lo cual tampoco nos dará un quebradero de cabeza a la hora de comprar la licencia como otras bases de datos comerciales, pues es totalmente gratuita.

Instalación de MongoDB en Debian 10

# Nos pasamos a root
sudo su

# Importamos la clave GPG de MongoDB
apt update
apt -y install gnupg2
wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | apt-key add -

# Añadimos el repositorio de MongoDB
echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main" | tee /etc/apt/sources.list.d/mongodb-org.list

# Actualizamos los repositorios
apt-get update

# Instalamos la última versión estable:
apt-get install -y mongodb-org

# Para activar el servicio de MongoDB en el arranque:
systemctl enable --now mongod

# Podemos comprobar el estado de MongoDB con:
systemctl status mongod.service

# Obtendremos algo como:
root@dwes:/home/veiga# systemctl status mongod.service
● mongod.service - MongoDB Database Server
   Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-12-04 23:35:46 CET; 30s ago
     Docs: https://docs.mongodb.org/manual
 Main PID: 13262 (mongod)
   Memory: 105.0M
   CGroup: /system.slice/mongod.service
           └─13262 /usr/bin/mongod --config /etc/mongod.conf

Dec 04 23:35:46 dwes systemd[1]: Started MongoDB Database Server.


# Para ver el puerto en el que está escuchando:
ss -tunelp

# Y veremos que está escuchando en localhost (127.0.0.1) y en el puerto 27017

root@dwes:/home/veiga# ss -tunelp
Netid  State   Recv-Q  Send-Q   Local Address:Port    Peer Address:Port
udp    UNCONN  0       0              0.0.0.0:68           0.0.0.0:*     users:(("dhclient",pid=287,fd=7)) ino:10558 sk:1 <->
tcp    LISTEN  0       20           127.0.0.1:25           0.0.0.0:*     users:(("exim4",pid=797,fd=3)) ino:13855 sk:2 <->
tcp    LISTEN  0       128            0.0.0.0:443          0.0.0.0:*     users:(("nginx",pid=425,fd=9),("nginx",pid=424,fd=9)) ino:12197 sk:3 <->
tcp    LISTEN  0       128          127.0.0.1:27017        0.0.0.0:*     users:(("mongod",pid=13262,fd=11)) uid:109 ino:68111 sk:4 <->
tcp    LISTEN  0       80           127.0.0.1:3306         0.0.0.0:*     users:(("mysqld",pid=422,fd=22)) uid:107 ino:12319 sk:5 <->
tcp    LISTEN  0       128            0.0.0.0:80           0.0.0.0:*     users:(("nginx",pid=425,fd=6),("nginx",pid=424,fd=6)) ino:12194 sk:6 <->
tcp    LISTEN  0       128            0.0.0.0:22           0.0.0.0:*     users:(("sshd",pid=534,fd=3)) ino:13324 sk:7 <->
tcp    LISTEN  0       128               [::]:443             [::]:*     users:(("nginx",pid=425,fd=8),("nginx",pid=424,fd=8)) ino:12196 sk:8 v6only:1 <->
tcp    LISTEN  0       128               [::]:80              [::]:*     users:(("nginx",pid=425,fd=7),("nginx",pid=424,fd=7)) ino:12195 sk:9 v6only:1 <->
tcp    LISTEN  0       128               [::]:22              [::]:*     users:(("sshd",pid=534,fd=4)) ino:13335 sk:a v6only:1 <->

# El puerto de escucha lo podríamos modificar editando el fichero /etc/mongod.conf:
nano /etc/mongod.conf

# En la sección de network interfaces modificaremos los datos que queramos:

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

# Una vez hechos los cambios reiniciamos con:
systemctl restart mongod.service

El shell de MongoDB

Para acceder a MongoDB desde el shell haremos:

mongo

# Para salir teclearemos:
exit

Cómo configurar la autenticación en MongoDB

# Primero conectaremos a mongoDB 
mongo

# Si estuviera configurado para un puerto diferente, por ejemplo el 27017:
mongo --port 27017

# Vamos a crear un usuario admin en la base de datos admin:
# Nos conectamos a la base de datos admin:
> use admin;

# Creamos el usuario:
> db.createUser(
  {
    user: "admin",
    pwd: "abc123.",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)
> exit
bye


# Abrimos /etc/mongod.conf
nano /etc/mongod.conf

# Habilitamos la autenticación

security:
  authorization: enabled

# Reiniciamos el servicio:
systemctl restart mongod

# Probamos a conectarnos a la base de datos testdb con el usuario dbadmin:
mongo -u "dbadmin" -p "abc123." --authenticationDatabase "admin"

# El usuario administrador tiene permisos para crear y gestionar la base de datos de usuarios. Si queremos leer o escribir en la base de datos tendremos que crear un usuario adicional con permisos de lectura y escritura en la base de datos.

# Si queremos crear usuarios para una base de datos específica:

# Nos conectamos a la base de datos. Si no existe la creará automáticamente:
use test

# Podemos usuar la funcion db.createUser() para crear un usuario para nuestra base de datos. La palabra clave db, hace referencia a la base de datos actual con la que estamos trabajando.

db.createUser(
  {
    user: "testUser",
    pwd: "xyz123",
    roles: [ { role: "readWrite", db: "test" } ]
  }
)

# Ahora podemos loguearnos en la base de datos "test" con el usuario testUser con permisos de lectura y escritura.
mongo --port 27017 -u "testUser" -p "xyz123" --authenticationDatabase "test"

# Para ver la base de datos en la que estamos trabajando, teclear:
db

Insertando datos en MongoDB

Insertando datos en MongoDB

Consultas en MongoDB

Actualizando datos en MongoDB

Borrando datos en MongoDB

Una característica realmente poderosa de npm es que permite de una forma rápida, fácil y consistente que otros desarrolladores inicien su código en su entorno local. Los proyectos de Node normalmente incluyen un archivo especial llamado package.json que incluye información sobre el proyecto, así como una lista de todos los paquetes npm de los que depende el proyecto.

Un desarrollador con una copia de su código local puede simplemente ejecutar npm install para tener cada dependencia descargada e instalada localmente usando este archivo package.json.

El indicador de instalación de npm --save o --save-dev es obligatorio si se desea que la dependencia que se está instalando sea guardada como referencia dentro del archivo package.json. Si estás comenzando un nuevo proyecto y no desea crear un archivo package.json a mano, simplemente puede ejecutar npm init y responder a algunas preguntas rápidas para obtener un paquete predeterminado.json configurado rápidamente.

Puede dejar cada pregunta en blanco durante init y aceptar los valores predeterminados si se desea:

$ npm init
$ npm install express --save
$ npm install grunt --save-dev
$ cat package.json
{
 "name": "chapter3",
 "version": "0.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "dependencies": {
   "express": "^3.5.1"
 },
 "devDependencies": {
   "grunt": "^0.4.4"
 }
}

Creación de un servidor web en Nodejs

Una de las grandes ventajas de Nodejs es su simplicidad. A diferencia de PHP o ASP en NodeJS no hay separación entre el servidor web y el propio código de la aplicación, ni tampoco tenemos que editar grandes ficheros de configuración para definir un comportamiento concreto. Con Node creamos el servidor, lo configuramos y entregamos el contenido y todo a nivel de código.

Vamos a ver cómo crear un servidor web con Node y enviar contenido a través de él, con seguridad y eficiencia.

Para poder enviar contenido web necesitamos crear una URI (Universal Resource Identifier) que identifique el recurso al que queremos acceder. En otras palabras crear las diferentes rutas de la aplciación que mostrarán las diferentes páginas o contenidos de la web.

Lo primero que haremos será crear nuestro fichero de servidor. Por ejemplo le llamamos server.js

El proceso consistiría en:

  1. Escribir todo el código del servidor web y de nuestra aplicación dentro del fichero server.js.
  2. Guardar el fichero server.js
  3. Arrancar la aplicación con el comando: node server.js
  4. Y así una y otra vez, cada vez que hagamos modificaciones en el fichero.

Para evitar el tener que ejecutar el comando: node server.js cada vez que modifiquemos la aplicación, podemos utilizar una aplicación adicional llamada hotnode, que se encargará de reiniciar nuestra aplicación cada vez que modifiquemos el fichero server.js.

Instalamos hotnode de forma global, para utilizarlo más adelante con nuestro server:

# Instalamos hotnode globalmente
npm -g install hotnode

# Para ejecutar el servidor:
hotnode server.js

# Hotnode auto-reiniciará nuestro servidor cada vez que grabemos las modificaciones en el fichero.

Para crear el servidor web necesitamos un módulo denominado http, que instalaremos dentro de la carpeta dónde tendremos nuestro servidor:

# Instalamos el módulo http:
npm install http

# Código que va dentro del fichero server.js:

var http = require('http');
http.createServer(function (request, response)
{
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.end('Funciona mi servidor con Node.js!');
}).listen(8080);

# Si estamos utilizando el VPS de Google tendremos que abrir en el firewall el puerto 8080 para permitir dicho tráfico al servidor:
# Lo haremos en:

Google Cloud Platform -> Red de VPC -> Reglas de cortafuegos

# Agregaremos una regla:
# Nombre: nodejs
# Descripción:  Para acceder al servidor de Node en 8080
# Destinos: Todas las instancias de la red
# Intervalos de IPs de origen: 0.0.0.0/0
# Protocolos y puertos: 
#  tcp: 8080
# Pulsamos el boton Crear.


# Para comprobar si funciona nuestro servidor web, nos tendremos que conectar a nuestro dominio pero al puerto 8080.
# Por ejemplo:

http://veiga.dynu.net:8080/

# Y se mostrará el mensaje:
Funciona mi servidor con Node.js!


Veiga (discusión) 00:30 5 dic 2019 (CET)