<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ nodejs - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ nodejs - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 13 Jun 2026 14:16:32 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/tag/nodejs/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo escribir Pruebas usando el Ejecutor de Pruebas de Node.js y mongodb-memory-server ]]>
                </title>
                <description>
                    <![CDATA[ Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-escribir-pruebas-usando-el-ejecutor-de-pruebas-de-node-js-y-mongodb-memory-server/</link>
                <guid isPermaLink="false">67bd1d95f9cd6804c5816fa9</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mongo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pruebas unitarias ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Tue, 15 Apr 2025 14:27:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2025/02/Captura-desde-2025-02-24-22-33-31.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-write-tests-using-the-nodejs-test-runner-and-mongodb-memory-server/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Write Tests Using the Node.js Test Runner and mongodb-memory-server</a>
      </p><p>Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo de ejecución de las pruebas fue reducido cerca de un 66%.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738830673460/1560f7a3-38c1-42f3-8944-df06b40d73e4.png" class="kg-image" alt="76% reduction in time taken to run tests in Jest vs Node.js test runner" width="560" height="478" loading="lazy"></figure><p>Decidí compartirte cómo pude implementarlo. Pienso que te será de utilidad, ya que es más rentable (en términos de reducir dinero gastado en ejecutar pruebas en CI/CD), y también mejora tu experiencia de desarrollo.</p><h2 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h2><ul><li><a href="#pre-requisitos">Pre-requisitos</a></li><li><a href="#ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</a></li><li><a href="#servidor-memoria-mongodb">El Servidor en memoria de MongoDB</a></li></ul><!--kg-card-begin: markdown--><ul>
<li><a href="#como-escribir-pruebas">Cómo escribir las Pruebas</a>
<ol>
<li><a href="#configurar-proyecto">Configurar el Proyecto</a></li>
<li><a href="#configurar-esquema-mongoose">Configurar el Esquema de Mongoose</a></li>
<li><a href="#configurar-servicios">Configurar los Servicios</a></li>
<li><a href="#configurar-pruebas">Configurar las Pruebas</a></li>
<li><a href="#escribir-pruebas">Escribir las Pruebas</a></li>
<li><a href="#pasar-pruebas">Pasar las Pruebas</a></li>
<li><a href="#usa-typescript-opcional">Usar TypeScript (Opcional)</a></li>
</ol>
</li>
</ul>
<!--kg-card-end: markdown--><ul><li><a href="#conclusion">Conclusión</a></li></ul><!--kg-card-begin: html--><h2 id="pre-requisitos">Pre-requisitos</h2><!--kg-card-end: html--><p>Para seguir esta guía, deberías de tener experiencia trabajando con Node.js, MongoDB y Mongoose (o cualquier otro mapeador de datos de objetos de MongoDB). Deberías también tener instalado Node.js (al menos la versión 20.18.2) y MongoDB (Compass la versión GUI) en tu computadora.</p><!--kg-card-begin: html--><h2 id="ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</h2><!--kg-card-end: html--><p>El ejecutor de pruebas de Node.js fue introducido como una característica experimental en la versión 18 de Node.js. Se volvió disponible oficialmente en la versión 20. Te da la habilidad de:</p><ol><li>Ejecutar pruebas</li><li>Reportar resultados de las pruebas</li><li>Reportar cobertura de las pruebas (todavía experimental en la versión 23)</li></ol><p>Es una buena idea el usar el ejecutor de pruebas incorporado cuando se escriban pruebas en Node.js porque significa que tienes que usar menos dependencias externas. No necesitas instalar una librería externa (y sus dependencias entre pares) para ejecutar las pruebas.</p><p>El mejor ejecutor incorporado también es el más rápido. Basado en mi experiencia usándolo en dos proyectos (los cuales usaron Jest), vi mejoras de al menos una reducción del 66% en el tiempo que tomó ejecutar las pruebas completamente.</p><p>Y a diferencia de otros frameworks o librerías de pruebas, el ejecutor de pruebas de Node.js fue construido especialmente para proyectos de Node.js. No trata de acomodar las especificaciones de otros entornos de programación como el navegador. Las especificaciones de Node.js son su principal y única prioridad.</p><!--kg-card-begin: html--><h2 id="servidor-memoria-mongodb">El Servidor en memoria de MongoDB</h2><!--kg-card-end: html--><p>Para las pruebas que involucran el hacer peticiones a una base de datos, algunos desarrolladores prefieren imitar las peticiones para evitar hacer peticiones a una base de datos real. Hacen esto porque hacer una petición a una base de datos real requiere un montón de configuraciones que puede costar tiempo y recursos.</p><p>Escribir y solicitar datos usando una base de datos real es más lento <a href="https://www.mongodb.com/resources/basics/databases/in-memory-database">comparado con escribir y solicitar datos de la memoria</a>. Cuando se ejecutan pruebas automatizadas, usando un servidor de MongoDB real será más lento que usar un servidor de base de datos en memoria, y ahí es donde <a href="https://github.com/typegoose/mongodb-memory-server">mongodb-memory-server</a> se vuelve útil.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738832586702/62360547-70e8-4e74-854f-c7ad74d182ea.png" class="kg-image" alt="Comparison between memory and database communication with CPU" width="631" height="256" loading="lazy"></figure><p>Según su documentación, mongodb-memory-server crea y comienza un servidor de MongoDB real de forma programática desde dentro de Node.js, pero usa una base de datos en memoria por defecto. También te permite conectar el servidor de base de datos que crea usando tu mapeador de datos de objetos preferido tales como Mongoose, Prisma, o TypeORM. En esta guía, usaremos <a href="https://mongoosejs.com/">Mongoose</a> (v.8.9.6).</p><p>Ya que los datos almacenados por mongodb-memory-server reside en la memoria por defecto, es más rápido leer y escribir en él que cuando se usa una base de datos real. mongodb-memory-server también es más fácil de configurar. Estos beneficios lo hace una buena elección para usarlo como un servidor de base de datos para escribir pruebas.</p><p><strong>Nota</strong>: asegúrate de instalar la versión 9.1.6 de mongodb-memory-server para seguir esta guía. La versión 10 actualmente tiene problemas con limpiar los recursos después que se hacen las pruebas. Mira este problema con el título "<a href="https://github.com/typegoose/mongodb-memory-server/issues/912">Node forking will include any <code>--import</code> from the original command</a>".</p><p>El problema ha sido resuelto al tiempo de escribir este artículo, pero el arreglo no ha sido fusionado para las instalaciones.</p><!--kg-card-begin: html--><h2 id="como-escribir-pruebas">Cómo escribir las Pruebas</h2><!--kg-card-end: html--><p>Ahora te guiaré a través de los siguientes pasos para que comiences a escribir las pruebas:</p><ol><li>Configurar el proyecto</li><li>Configurar el esquema de Mongoose</li><li>Configurar los servicios</li><li>Configurar las pruebas</li><li>Escribir las pruebas</li><li>Pasar las pruebas</li><li>Usa TypeScript (Opcional)</li></ol><!--kg-card-begin: html--><h3 id="configurar-proyecto">1. Configurar el Proyecto</h3><!--kg-card-end: html--><p>Creé un repositorio de Github para facilitarte que sigas esta guía. Clona este repositorio en <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a> y dirígete a la rama <code>01-setup</code>. </p><p>En <code>01-setup</code>, las dependencias para el proyecto están el archivo <code>package.json</code>. Instala las dependencias usando el comando <code>npm install</code> para configurar el proyecto. Asegúrate de que la configuración esté completa y correcta, ejecuta el comando <code>node .</code> en la terminal de tu proyecto. Deberías ver tu versión de Node.js &nbsp;como una salida en la terminal.</p><pre><code class="language-bash"># instala las dependencias
npm install
...
# ejecuta el comando node
node .
# la salida
You are running Node.js v22.13.1
</code></pre><!--kg-card-begin: html--><h3 id="configurar-esquema-mongoose">2. Configurar el Esquema de Mongoose</h3><!--kg-card-end: html--><p>Configuraremos el esquema para dos colecciones (Task y User) en la rama <code>02-setup-schema</code> usando Mongoose. Los archivos <code>task/model.mjs</code> y <code>user/model.mjs</code> contienen el esquema para las colecciones Task y User, respectivamente. También configuraremos una conexión de base de datos en <code>index.mjs</code> para asegurar que la configuración del esquema funcione correctamente.</p><p>No iré en detalle sobre los modelos y esquemas de Mongoose en este artículo porque están fuera de su alcance.</p><p>Cuando ejecutas el comando <code>node .</code> después de implementar los cambios en <code>02-setup-schema</code>, deberías de ver un resultado similar en la consola como en el fragmento de abajo:</p><pre><code class="language-bash">node .
You are running Node.js v22.13.1
Created user with id 679f1d7f73fbeaf23b2007df
Created task "Task title" for user with id "679f1d7f73fbeaf23b2007df"
</code></pre><p>Puedes ver las diferencias entre <code>01-setup</code> y <code>02-setup-schema</code> a través de la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia 01-setup &lt;&gt; 02-setup-schema en Github</a>. </p><!--kg-card-begin: html--><h3 id="configurar-servicios">3. Configurar los Servicios</h3><!--kg-card-end: html--><p>Luego, creamos los archivos de servicio (<code>task/service.mjs</code> y <code>user/service.mjs</code>) en la rama <code>03-setup-services</code>. Ambos archivos actualmente contienen funciones vacías en el que escribiremos las pruebas más tarde. Estas funciones contendrán la lógica de negocio y también se comunicará con la base de datos. Estamos usando comentarios de <a href="https://jsdoc.app/">JSDoc</a> para escribir parámetros y regresar valores.</p><p>Haz clic en la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia de 02-setup-schema &lt;&gt; 03-setup-services</a> para ver los cambios de código entre <code>02-setup-schema</code> y <code>03-setup-services</code>.</p><!--kg-card-begin: html--><h3 id="configurar-pruebas">4. Configurar las Pruebas</h3><!--kg-card-end: html--><p>En la rama <code>04-set-up-tests</code>, configuramos la base de código para ejecutar las pruebas. Creamos <code>test.setup.mjs</code> el cual contiene el código que será ejecutado antes de que cada archivo de prueba se ejecute.</p><p>En <code>test.setup.mjs</code>, la función <code>connect</code> crea un servidor de MongoDB en memoria y lo conecta con Mongoose para ejecutar las pruebas. La función <code>closeDatabase</code> cierra la conexión de la base de datos y limpia todos los recursos para liberar memoria.</p><p>Las funciones <code>connect</code> y <code>closeDatabase</code> se ejecutan en el hook <code>t.before</code> y en el hook <code>t.after</code> respectivamente. Esto asegura eso, antes que un archivo test se ejecute, una conexión de base de datos se establece a través <code>t.before</code>. Luego de que se hayan ejecutado las pruebas del archivo, la conexión de la base de datos se cae y los recursos usados se limpian a través de <code>t.after</code>.</p><p>En <code>package.json</code>, actualizaremos el script de npm <code>test</code> a <code>node --test --import ./test.setup.mjs</code>. Este comando asegura que Módulo Es <code>test.setup.mjs</code> se pre-cargue y se ejecute a través del comando <code>--import</code> del CLI antes de que cada archivo de prueba se ejecute.</p><p>Luego crearemos los archivos de prueba con pruebas vacías en las carpetas <code>__tests__</code> para <code>user</code> y <code>task</code>. Después de implementar los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/03-setup-services...04-set-up-tests">nuevos cambios en 04-set-up-tests</a>, ejecutar el script <code>test</code> con <code>npm run test</code> debería de mostrar la salida similar al fragmento de abajo:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 8
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 941.768873
</code></pre><p>Todas las pruebas actualmente pasan porque no hay aserciones que fallen. Escribiremos las pruebas con aserciones en la siguiente sección.</p><!--kg-card-begin: html--><h3 id="escribir-pruebas">5. Escribir Pruebas</h3><!--kg-card-end: html--><p>Ahora es tiempo de escribir las pruebas para las funciones en los archivos de service en la rama <code>05-write-tests</code>. Estamos usando la librería de aserción de Node.js para asegurar que los valores regresados de las funciones sean lo que esperamos. Puedes ver las pruebas que hemos escrito cuando comparas <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/04-set-up-tests...05-write-tests">las diferencias entre 04-set-up-tests y 05-write-tests</a>.</p><p>Cuando el script <code>tests</code> se ejecute, todas las pruebas fallan porque no hemos escritos las funciones en los archivos de service todavía. Debería de ver una salida similar al fragmento de abajo cuando ejecutes el script <code>test</code>:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 0
ℹ fail 8
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1202.031961
</code></pre><!--kg-card-begin: html--><h3 id="pasar-pruebas">6. Pasar las Pruebas</h3><!--kg-card-end: html--><p>En <code>06-pass-tests</code>, escribimos las funciones en los archivos de service que pasen las pruebas. Solamente 6 de 7 pruebas pasan cuando el script <code>test</code> se ejecuta porque salteamos la prueba para la función <code>getById</code> en <code>user/service.mjs</code> con <code>t.skip</code>. No hemos terminado la función <code>getById</code> en <code>user/service.mjs</code>. Supuse que podríamos dejarlo como ejercicio.</p><p>Cuando ejecutas el script <code>test</code>, deberías obtener una salida similar en la terminal como el de abajo:</p><pre><code class="language-bash">ℹ tests 7
ℹ suites 4
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 1287.564918
</code></pre><p>Puedes ver el código que escribimos para pasar las pruebas en los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/05-write-tests...06-pass-tests">cambios de código entre 05-write-tests y 06-pass-tests</a>.</p><!--kg-card-begin: html--><h3 id="usa-typescript-opcional">7. Usa TypeScript (Opcional)</h3><!--kg-card-end: html--><p>Si tu intención es ejecutar las pruebas con TypeScript, puedes cambiar a la rama <code>07-with-typescript</code>. Necesitas tener Node.js <code>&gt;=22.6.0</code> instalado porque estamos usando la opción <code>--experimental-strip-types</code> en el <code>test</code>. Para configurar las pruebas que se ejecuten con TypeScript, sigue los siguientes pasos:</p><ol><li>Instala TypeScript usando el comando <code>npm install typescript --save-dev</code> </li><li>Instala tsx usando el comando <code>npm install tsx</code></li><li>Crea un archivo predeterminado <code>tsconfig.json</code> en la raíz del proyecto usando el comando <code>npx tsc --init</code> </li></ol><p>En &nbsp;<code>package.json</code>, actualiza el script <code>test</code> a esto:</p><pre><code class="language-bash">"test": "node --test --experimental-strip-types --import tsx --import ./test.setup.mjs"
</code></pre><ul><li><a href="https://nodejs.org/docs/latest-v22.x/api/cli.html#--experimental-strip-types"><code>--experimental-strip-types</code></a> ayuda a eliminar tipos antes de cada archivo de prueba se ejecute.</li></ul><p>Pre-cargar <code>tsx</code> con el <code>--import</code> ayuda a ejecutar el archivo de TypeScript. Sin él, el ejecutor de pruebas no será capaz de encontrar archivos importados sin la extensión <code>.ts</code>. Por ejemplo, <code>user/model.ts</code> importado con el fragmento de código de abajo no será encontrado.</p><pre><code class="language-typescript">  import { UserModel } from "./model";
</code></pre><p>El resto de los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/06-pass-tests...07-with-typescript">cambios desde 06-pass-tests a 07-with-typescript</a> involucran actualizar los tipos, cambiar las extensiones de archivo de <code>.mjs</code> a <code>.ts</code> y actualizar las declaraciones import.</p><!--kg-card-begin: html--><h2 id="conclusion">Conclusión</h2><!--kg-card-end: html--><p>En esta guía, has aprendido cómo usar el ejecutor de pruebas incorporado de Node.js y por qué es frecuentemente una mejor elección sobre otras librerías y frameworks de pruebas. También has aprendido cómo usar mongodb-memory-server como un reemplazo de un servidor real de MongoDB, así también como por qué es una buena idea usarlo en vez de un servidor real de MongoDB para las pruebas.</p><p>Lo más importante, has aprendido cómo configurar y ejecutar las pruebas en Node.js usando el ejecutor de pruebas de Node.js y mongodb-memory-server. Ahora deberías de saber cómo configurar tus proyectos para que ejecuten las pruebas si usas TypeScript.</p><p>Si encuentras útil a este repositorio <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a>, por favor dale una estrella. Me anima mucho. Gracias.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Un vistazo rápido a Bun 1.0 - Una alternativa a Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido". Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0. ¿Cómo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/un-vistazo-rapido-a-bun-1-0-una-alternativa-a-node-js/</link>
                <guid isPermaLink="false">65c24f33aa1f2203f0eb0f2e</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ bun ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Wed, 14 Feb 2024 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="un-hombre-sabio-me-dijo-una-vez-cuando-empieces-a-comer-bun-panecillo-node-js-se-sentir-ins-pido-">Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido".</h3><p>Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0.</p><p>¿Cómo y por qué es más rápido que Node.js? Me vienen a la mente muchas preguntas.</p><p>Responderé algunas de esas preguntas en este artículo. Y lo haré rápidamente, ya que ahora soy más rápido, al igual que JavaScript, que se prepara con Bun 1.0.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--3-.gif" class="kg-image" alt="But-why-is-that-relevant--3-" width="600" height="400" loading="lazy"></figure><p><strong>Bun es un conjunto de herramientas rápidas todo en uno para ejecutar, crear, probar y depurar JavaScript y TypeScript</strong>, desde un único archivo hasta una aplicación <em>full-stack</em>.</p><p>A continuación algunas cosas que podemos hacer con Bun:</p><h2 id="ejecuta-tu-c-digo-m-s-r-pido-con-bun">Ejecuta tu código más rápido con Bun</h2><p>Ahora no necesitamos herramientas como <code>npm</code>, <code>pnpm</code> o <code>yarn</code> porque Bun es 17 veces mas rápido. Eche un vistazo a los datos mostrados a continuación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png" class="kg-image" alt="266451126-23cbde35-b859-41b5-9480-98b88bf40c44" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/size/w2400/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 2400w" sizes="(min-width: 720px) 720px" width="2680" height="1324" loading="lazy"><figcaption>Comparación de velocidades entre Bun, pnpm, npm y yarn</figcaption></figure><p>Bun tarda solo 0,36 segundos en compilar su código, mientras que tarda unos 6,44 segundos en el caso de pnpm, 10,58 segundos con npm y 12,08 segundos con yarn.</p><h2 id="bun-soporta-hot-reloading">Bun soporta <em>hot reloading</em></h2><p>Bun soporta <em>hot reloading</em> (recarga en caliente) desde el primer momento, por lo que no necesita herramientas como Nodemon. Actualizará automáticamente el servidor cuando se ejecute JavaScript o TypeScript.</p><p>Puede reemplazar el comando <code>npm run</code> con <code>bun run</code> para ahorrar más de 150 ms milisegundos cada vez que ejecuta un comando.</p><p>Aquí un gráfico completo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png" class="kg-image" alt="Screenshot-2023-09-14-at-7.17.45-PM-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1198w" sizes="(min-width: 720px) 720px" width="1198" height="434" loading="lazy"><figcaption>Promedio de tiempos de <em>hot realoding </em>usando diferentes paquetes</figcaption></figure><p>Según el cuadro anterior, el uso de <code>npm</code> tarda unos 176 ms en ejecutarse, <code>yarn</code> tarda unos 131 ms. En el caso de <code>pnpm</code>, se necesitan 259 ms. Sin embargo, en el caso de Bun, se necesitan unos 7 ms. Eso es rápido, ¿no?</p><h2 id="bun-es-un-empaquetador-javascript">Bun es un empaquetador JavaScript</h2><p>Bun también es un empaquetador de JavaScript con el mejor rendimiento de su clase y una API compatible con ESBuild, por lo que no necesitamos cosas como:</p><ul><li>ESBuild</li><li>Webpack</li><li>Parcel, .parcelrc</li><li>Rollup, rollup.config.js</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.gif" class="kg-image" alt="But-why-is-that-relevant--2-" width="1920" height="1080" loading="lazy"></figure><p>Bun ahora soporta Next.js, Remix, Nuxt, Astro, SvelteKit, Nest, SolidStart y Vite.</p><h2 id="bun-es-compatible-con-esm-y-commonjs">Bun es compatible con ESM y CommonJS</h2><p>Otra gran característica de Bun es que podemos usar módulos ES6 y CommonJs juntos en el mismo archivo, lo que no era posible en Node.js.</p><p>Puedes usar <code>import</code> y <code>require()</code> en el mismo archivo:</p><figure class="kg-card kg-code-card"><pre><code class="language-js">import lodash from "lodash";
const _ = require("underscore");</code></pre><figcaption>ESM y CommonJs en el mismo archivo</figcaption></figure><p>Aparte de eso, Bun tiene soporte integrado para las API estándar web que están disponibles en los navegadores, como <code>fetch</code>, junto con la propia API de Bun como <code>Bun.file()</code> para leer un archivo de forma diferida y <code>Bun.Write()</code> para escribir un archivo al sistema de archivos local, que es mucho más simple que Node.js.</p><h2 id="ejemplo-bun-file-">Ejemplo <code>Bun.file()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">const archivo = Bun.file("package.json");
const contenido = await archivo.text();
</code></pre><figcaption>Leemos archivos del sistema de archivos con Bun</figcaption></figure><p>El código anterior leerá el contenido de un archivo <code>package.json</code> y transferirá su contenido a una nueva variable llamada <code>contenido</code>.</p><h2 id="ejemplo-bun-write-">Ejemplo <code>Bun.write()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">await Bun.write("index.html", "&lt;html/&gt;");
await Bun.write("index.html", Buffer.from("&lt;html/&gt;"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", 
await fetch("https://ejemplo.com/"));</code></pre><figcaption>Escribimos archivos en el sistema de archivos</figcaption></figure><p>En el código anterior, <code>Bun.write()</code> escribirá la cadena <code>"&lt;html/&gt;"</code>, o copiará el contenido del archivo <code>home.html</code> en el archivo <code>index.html</code>. Si tenemos que recuperar datos, obtendrá los resultados de una API web externa y escribirá el contenido en un archivo <code>index.html</code>.</p><h2 id="-por-que-bun-es-tan-r-pido">¿Por que Bun es tan rápido?</h2><p>Bun es rápido porque usa el motor JavaScriptCore, mientras que Node.js usa el motor JavaScript V8. El primero se ha optimizado para un tiempo de inicio más rápido.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png" class="kg-image" alt="But-why-is-that-relevant" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/But-why-is-that-relevant.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/But-why-is-that-relevant.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="900" loading="lazy"><figcaption>Bun usa JavaScriptCore | Node usa V8</figcaption></figure><p>Si deseas hacer las cosas más rápido, debería considerar reemplazar Node.js con Bun.</p><h2 id="-c-mo-empezar-a-usar-bun">¿Cómo empezar a usar Bun?</h2><p>Puedes instalar Bun en sistemas MacOS y Linux usando <code>npm</code>:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">npm install -g bun</code></pre><figcaption>Comando para instalar Bun en MacOs y distribuciones Linux</figcaption></figure><p>Ahora ya está todo listo. Para instalar un paquete <code>npm</code>, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun install &lt;nombre-paquete&gt;</code></pre><figcaption>Comando para instalar paquetes usando Bun</figcaption></figure><p>Para iniciar una aplicación, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun run dev</code></pre><figcaption>Ejecutar una app Next.js</figcaption></figure><p>Para todo lo que pueda necesitar solo reemplace <code>npm</code> con <code>bun</code>.</p><p>Sin embargo, Bun sólo está listo para producción en los sistemas operativos MacOS y Linux. La versión de Windows aún es experimental. Por el momento, solo se admite el entorno de ejecución de JavaScript para Windows, y no el administrador de paquetes, el empaquetador ni el entorno de pruebas. <a href="https://bun.sh/docs/installation#windows">Puedes leer más al respecto aquí</a>.</p><h1 id="conclusi-n">Conclusión</h1><p>Este artículo muestra cómo puedes utilizar Bun como alternativa a Node.js y acelerar su tiempo de desarrollo.</p><p>También puedes ver mi vídeo sobre <a href="https://www.youtube.com/watch?v=q5UKY_dCmh4"><strong>El asesino de Node.js está aquí — Primer vistazo a Bun 1.0</strong></a><strong> (en inglés)</strong>.</p><p>Gracias por leer.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo usar Nodemailer para enviar correos electrónicos desde tu servidor Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Nodemailer [https://nodemailer.com/about/] es un módulo de Node.js que te permite enviar emails desde tu servidor con facilidad. Sea que quieras comunicarte con tus usuarios o sólo notificarte a ti mismo cuando algo ha salido mal, una de las opciones para hacerlo es a través de un email. Hay muchos artículos ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-usar-nodemailer-para-enviar-correos-electronicos-desde-tu-servidor-node-js/</link>
                <guid isPermaLink="false">64b7ce217c3604085152d6fa</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Wed, 16 Aug 2023 13:50:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/07/600efb510a2838549dcb7595.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/use-nodemailer-to-send-emails-from-your-node-js-server/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use Nodemailer to Send Emails from Your Node.js&nbsp;Server</a>
      </p><p><a href="https://nodemailer.com/about/">Nodemailer</a> es un módulo de Node.js que te permite enviar emails desde tu servidor con facilidad. Sea que quieras comunicarte con tus usuarios o sólo notificarte a ti mismo cuando algo ha salido mal, una de las opciones para hacerlo es a través de un email.</p><p>Hay muchos artículos por ahí que explican cómo usar Nodemailer de forma muy básica, pero este artículo no es uno de ellos. Aquí, te mostraré la práctica más común de enviar un email desde tu backend Node.js usando Nodemaier y Gmail. </p><h2 id="c-mo-empezar-con-nodemailer"><strong>Cómo empezar con Nodemailer</strong></h2><p>Primero, necesitamos configurar nuestro boilerplate de Node.js usando Express. Para asegurarte que tienes Node y npm instalados, puedes ejecutar los siguientes comandos:</p><pre><code class="language-bash">node -v 
npm -v</code></pre><p>Si ambos de estos comandos muestran una versión, puedes continuar. De otra manera, instala lo que falta.</p><p>Crea una carpeta para tu proyecto. Usaremos el nombre <strong>nodemailerProject</strong>.</p><pre><code class="language-bash">mkdir nodemailerProject</code></pre><p>Ve dentro de la nueva carpeta creada y ejecuta:</p><pre><code class="language-bash">npm init</code></pre><p>Esto iniciará nuestro proyecto con un archivo <strong>package.json</strong>.</p><p>Lo siguiente, necesitaremos instalar Express usando:</p><pre><code class="language-bash">npm install express</code></pre><p>Dependiendo qué archivo señalaste como tu punto de entrada (por defecto es index.js), ábrelo y pega el siguiente código:</p><figure class="kg-card kg-code-card"><pre><code class="language-js">const express = require('express')
const app = express()
const port = 3000


app.listen(port, () =&gt; {
  console.log(`nodemailerProject is listening at http://localhost:${port}`)
})</code></pre><figcaption>index.js</figcaption></figure><p>Lo de arriba es lo que se necesita para empezar un simple servidor usando Express. Puedes ver que está funcionando adecuadamente ejecutando:</p><pre><code class="language-bash">node index.js</code></pre><h3 id="c-mo-instalar-nodemailer"><strong>Cómo instalar Nodemailer</strong></h3><p>Instala nodemailer usando el siguiente comando:</p><pre><code class="language-bash">npm install nodemailer</code></pre><p>La API de Nodemailer es bastante sencillo y nos pide que hagamos lo siguiente:</p><ol><li>Crea un objeto <strong><strong>Transporter</strong></strong></li><li>Crea un objeto <strong><strong>MailOptions </strong></strong></li><li>Usa el método <strong><strong>Transporter.sendMail</strong></strong> </li></ol><p>Para crear un objeto transporter, hacemos lo siguiente:</p><pre><code class="language-js">let transporter = nodemailer.createTransport({
      service: 'gmail',
      auth: {
        type: 'OAuth2',
        user: process.env.MAIL_USERNAME,
        pass: process.env.MAIL_PASSWORD,
        clientId: process.env.OAUTH_CLIENTID,
        clientSecret: process.env.OAUTH_CLIENT_SECRET,
        refreshToken: process.env.OAUTH_REFRESH_TOKEN
      }
    });</code></pre><blockquote>✋ Presta atención, aparte de las claves de usuario y contraseña, los cuales son tus propias credenciales para tu cuenta de gmail, las otras tres claves necesitan ser recuperadas después de configurar OAuth.</blockquote><p>Como dijimos al principio de este artículo, estaremos usando Gmail para nuestras necesidades de envío de correo. Como habrás adivinado, Gmail tiene un alto nivel de seguridad cuando se trata de correo enviado por/a la cuenta de un usuario.</p><p>Hay varias formas que podemos superar este obstáculo (algunas mejores que las otras), y elegiremos la que nos pide configurar un proyecto en la <strong>Plataforma de Nube de Google</strong>. Necesitamos hacer eso para tener las credenciales para la seguridad de OAuth activado por Gmail.</p><blockquote><a href="https://nodemailer.com/usage/using-gmail/"></a><a href="https://nodemailer.com/usage/using-gmail/"></a><a href="https://nodemailer.com/usage/using-gmail/" rel="noopener">a</a>quí</blockquote><p>Los próximos pasos requerirán algunas configuraciones en vez de código, así que prepárense.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-297.png" class="kg-image" alt="image-297" width="600" height="400" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@d_mccullough?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Daniel McCullough</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><h2 id="configuraciones-de-la-plataforma-de-la-nube-de-google"><strong>Configuraciones de la Plataforma de la Nube de Google</strong></h2><p>Si no tienes una cuenta de la <a href="https://console.cloud.google.com/home">Plataforma de la Nube de Google</a>, asegúrate de configurar uno como pre-requisito. Una vez que lo hayas creado, crea un nuevo proyecto haciendo clic en el menú desplegable en la esquina izquierda superior.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_a4fnFLNMoTtLJuqsKilVnA.png" class="kg-image" alt="1_a4fnFLNMoTtLJuqsKilVnA" width="600" height="400" loading="lazy"></figure><p>Selecciona la opción New Project:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_HNwUG3wPdbrwc3JB5D7_tg.png" class="kg-image" alt="1_HNwUG3wPdbrwc3JB5D7_tg" width="600" height="400" loading="lazy"></figure><p>En la próxima ventana, tendremos que darle a nuestro proyecto un nombre. Elige cualquiera que te guste, pero continuaremos con nuestro nombre <strong>NodemailerProject</strong>. Para la propiedad <strong>location</strong>, puedes dejarlo como <strong>No organization</strong>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_TRlA6RBLCCCSMQ5R4di27A.png" class="kg-image" alt="1_TRlA6RBLCCCSMQ5R4di27A" width="600" height="400" loading="lazy"></figure><p>Podría tomar unos pocos segundos para que el proyecto se configure, pero luego de eso serás capaz de ver esta pantalla:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_FT9MhBZyU4cZd4Qg6zeFag.png" class="kg-image" alt="1_FT9MhBZyU4cZd4Qg6zeFag" width="600" height="400" loading="lazy"></figure><p>Abre el menú de navegación haciendo clic en las tres líneas punteadas en la esquina de arriba a la izquierda y selecciona <strong>APIs and Services</strong>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_qPaPpPadHQLdKCQbhjND7Q.png" class="kg-image" alt="1_qPaPpPadHQLdKCQbhjND7Q" width="600" height="400" loading="lazy"></figure><p>Para ser capaz de usar Nodemailer y Gmail tendremos que usar OAuth2. Si no estás familiarizado con OAuth, es un protocolo para autenticación. No voy a entrar en detalles aquí, ya que no es necesario, pero si quieres entender más sobre ello, ve <a href="https://oauth.net/2/">aquí</a>.</p><p>Primero tendremos que configurar nuestra OAuth Consent Screen:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_W2oeT1KmJXpwSQlIMIVo5w.png" class="kg-image" alt="1_W2oeT1KmJXpwSQlIMIVo5w" width="600" height="400" loading="lazy"></figure><p>Si no eres un miembro del G-Suite, la única opción disponible será <strong>External for user Type</strong>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_l_GrPVtXODPS0GXKLMdWYA.png" class="kg-image" alt="1_l_GrPVtXODPS0GXKLMdWYA" width="600" height="400" loading="lazy"></figure><p>Luego de hacer clic en crear, la próxima pantalla nos pide rellenar la información de la aplicación (nuestro servidor):</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_reZ04hUX4jh1IzLGh7vCFA.png" class="kg-image" alt="1_reZ04hUX4jh1IzLGh7vCFA" width="600" height="400" loading="lazy"></figure><p>Rellena tu email en el campo <strong>User Support</strong> y también en el campo <strong>Developer Contact Information</strong>. Haz clic en <strong>Save</strong> y <strong>Continue</strong> nos traerá a la fase <strong>Scopes</strong> de esta configuración. Omite esta fase, ya que no es relevante para nosotros, y dirígete a la <strong>fase Test Users</strong>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_Jms50wZ5mVmUyOaiVF7b4w.png" class="kg-image" alt="1_Jms50wZ5mVmUyOaiVF7b4w" width="600" height="400" loading="lazy"></figure><p>Aquí, añádete a ti mismo como un usuario y haz clic en <strong>Save</strong> y <strong>Continue</strong>.</p><h2 id="c-mo-configurar-tus-opciones-de-oauth"><strong>Cómo configurar tus Opciones de OAuth</strong></h2><p>En esta fase crearemos nuestras credenciales de OAuth para ser usados con Nodemailer. Dirígete a la pestaña <strong>Credentials</strong> sobre <strong>OAuth Consent Screen.</strong> Haz clic en el signo más (➕) que tiene el texto <strong>Create Credentials</strong> y elige OAuth Client ID.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_h0nME2ccR7HPjKmz_DMZRw.png" class="kg-image" alt="1_h0nME2ccR7HPjKmz_DMZRw" width="600" height="400" loading="lazy"></figure><p>En el menú desplegable de tipo de Aplicación, elige <strong>Web Application</strong>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_72Em-VS-fdM2WCwOA6zcfg.png" class="kg-image" alt="1_72Em-VS-fdM2WCwOA6zcfg" width="600" height="400" loading="lazy"></figure><p>En la sección de <strong>Authorized Redirect URIs</strong>, asegúrate de agregar <a href="https://developers.google.com/oauthplayground">OAuth2 Playground</a>, ya que lo usaremos para obtener una de las claves que fue mencionado al principio de este artículo.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_ywIcOlqA5DHdsPaSNnjJ9Q.png" class="kg-image" alt="1_ywIcOlqA5DHdsPaSNnjJ9Q" width="600" height="400" loading="lazy"></figure><p>Después de hacer clic en <strong>create</strong>, te será presentado tú id y secreto de cliente. <strong>Guárdalos y nunca los expongas de ninguna manera o forma.</strong> </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-298.png" class="kg-image" alt="image-298" width="600" height="400" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@welipower?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Power Lai</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><h3 id="obt-n-tu-token-de-actualizaci-n-de-oauth"><strong>Obtén tu Token de Actualización de OAuth</strong></h3><p>Para obtener un token de actualización, el cual usaremos dentro del objeto <strong>transporter</strong> en <strong>Nodemailer</strong>, necesitamos dirigirnos al Playground de OAuth2. Aprobamos este URI para este propósito específico en una etapa previa.</p><ol><li>Haz clic en el ícono de engranaje a la derecha (el cual es la Configuración de OAuth2) y verifica la casilla de verificación para usar tus propias Credenciales de OAuth2:</li></ol><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_Kbg3RnTBNkDd_RQ0zn59mQ.png" class="kg-image" alt="1_Kbg3RnTBNkDd_RQ0zn59mQ" width="600" height="400" loading="lazy"></figure><p>2. Mira a la parte izquierda del sitio web y verás una lista de servicios. Desplázate hacia abajo hasta que veas Gmail API v1.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_BppvkU1r4JzZ6j6FvC2qNw.png" class="kg-image" alt="1_BppvkU1r4JzZ6j6FvC2qNw" width="600" height="400" loading="lazy"></figure><p>3. Haz clic en <strong><strong>Authorize APIs</strong></strong></p><p>Te será presentado una pantalla para iniciar sesión con cualquiera de tus cuentas Gmail. Elige la que listaste como un usuario de Prueba.</p><p>4. La próxima pantalla te hará saber que Google todavía no ha verificado esta aplicación, pero esto está bien, ya que no lo hemos entregado para verificación. Haz clic en <strong>continue</strong>. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_rL0tNdaZqOyIg6aCp4IR3g.png" class="kg-image" alt="1_rL0tNdaZqOyIg6aCp4IR3g" width="600" height="400" loading="lazy"></figure><p>5. En la próxima pantalla, te preguntará para conceder permiso a tu proyecto para interactuar con tu cuenta de Gmail. Házlo. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/01/1_y0TUXbtC_oUaB6KoGlURbQ.png" class="kg-image" alt="1_y0TUXbtC_oUaB6KoGlURbQ" width="600" height="400" loading="lazy"></figure><p>6. Una vez que esto está hecho, serás redireccionado de vuelta al Plaground de OAuth y puedes ver que hay un código de autorización en el menú a la izquierda. Haz clic en el botón azul etiquetado <strong><strong>Exchange authorization code for tokens</strong></strong>.</p><p>Los campos para el token de actualización y el token de acceso estarán rellenados ahora.</p><h2 id="de-vuelta-al-servidor"><strong>De vuelta al Servidor</strong></h2><p>Después de hacer todas esas configuraciones, podemos volver a nuestra aplicación e ingresar todos esos datos en la creación de transporter. Para tener todas tus credenciales de manera privada, puedes usar el <a href="https://www.npmjs.com/package/dotenv">paquete dotenv</a>. No te olvides también de agregar el archivo .env que crearás en .gitignore.</p><p>Así que, ahora tenemos esto:</p><pre><code class="language-javascript">let transporter = nodemailer.createTransport({
      service: 'gmail',
      auth: {
        type: 'OAuth2',
        user: process.env.MAIL_USERNAME,
        pass: process.env.MAIL_PASSWORD,
        clientId: process.env.OAUTH_CLIENTID,
        clientSecret: process.env.OAUTH_CLIENT_SECRET,
        refreshToken: process.env.OAUTH_REFRESH_TOKEN
      }
    });</code></pre><p>Después, crearemos el objeto mailOptions, el cual tiene los detalles de a dónde enviar el email y con qué datos.</p><pre><code class="language-javascript">let mailOptions = {
      from: tomerpacific@gmail.com,
      to: tomerpacific@gmail.com,
      subject: 'Nodemailer Project',
      text: 'Hi from your nodemailer project'
    };</code></pre><p>Este objeto puede tener muchos más campos e inclusive múltiples recipientes, pero no veremos eso aquí.</p><p>Finalmente, usaremos el método sendMail:</p><pre><code class="language-javascript">transporter.sendMail(mailOptions, function(err, data) {
      if (err) {
        console.log("Error " + err);
      } else {
        console.log("Email sent successfully");
      }
    });</code></pre><p>Ejecuta tu aplicación y verás tu bandeja de entrada ser rellenado con un nuevo email.</p><p>Este artículo fue inspirado de un proyecto que creé que usa Nodemailer. Si quieres verlo, ve <a href="https://github.com/TomerPacific/ProjectChecker">aquí</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo crear una aplicación CRUD de línea de comandos con Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Si estás buscando un tutorial que te enseñe lo básico de Nodejs [https://nodejs.org/es/] y la línea de comando, estás en el lugar correcto. Puedes usar JavaScript para construir casi cualquier software (web, móvil, bots, etcétera). La razón es que las computadoras ya no dependen en los buscadores solamente para entender ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-aplicacion-crud-de-linea-de-comandos-con-node-js/</link>
                <guid isPermaLink="false">63f76d032154fe0736d61019</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Wed, 15 Mar 2023 14:35:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/02/pexels-hitesh-choudhary-1261427.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-build-a-command-line-application-with-nodejs/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build a CRUD Command Line Application With Node.js</a>
      </p><p>Si estás buscando un tutorial que te enseñe lo básico de <a href="https://nodejs.org/es/">Nodejs</a> y la línea de comando, estás en el lugar correcto.</p><p>Puedes usar JavaScript para construir casi cualquier software (web, móvil, bots, etcétera). La razón es que las computadoras ya no dependen en los buscadores solamente para entender código de JavaScript. </p><p>Node.js es usado para ejecutar aplicaciones backend que son escritos en JavaScript.</p><p>Te enseñare cómo construir una aplicación de línea de comando que puede leer, escribir, editar y eliminar datos usando Node.js. No requerirá conectar a bases de datos externos como MySQL, MongoDB, PostgreSQL, etcétera. Puedes ver el proyecto <a href="https://github.com/EBEREGIT/Nodejs_CLI_app">aquí</a>.<br><br>Al final de este artículo, serías capaz de configurar un proyecto básico de Node, manipular archivos, usar módulos, navegar promesas, recoger entradas, etcétera.<br><br>También agregué videos para mejorar tu aprendizaje.</p><h2 id="prerequisitos"><strong>Prerequisitos</strong></h2><p>No necesitas ningún conocimiento de programación previo para entender este tutorial.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/RQ4b0Ui1-3o?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid0" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><h2 id="c-mo-funcionar-el-proyecto-finalizado"><strong>Cómo funcionará el Proyecto Finalizado</strong></h2><p>La aplicación que vamos a construir será capaz de hacer lo siguiente:</p><ul><li>Chequear si existe una base de datos</li><li>Recuperar datos de una base de datos</li><li>Agregar nuevos datos a la base de datos</li><li>Actualizar la base de datos con nuevos datos</li><li>Remover datos de la base de datos</li></ul><h2 id="c-mo-instalar-node-y-npm"><strong>Cómo Instalar Node y NPM</strong></h2><p>Por favor ve a la <a href="https://nodejs.org/es/">página de Nodejs</a> y descarga la versión recomendada para todos los usuarios. Instálalo después de que la descarga esté completa.</p><p>Usa los comandos debajo para chequear si la instalación fue exitosa:</p><ul><li>Para Node</li></ul><pre><code class="language-bash">node -v</code></pre><ul><li>Para npm</li></ul><pre><code class="language-bash">npm -v</code></pre><p>La instalación es exitosa si cada comando regresa un número de versión.</p><h2 id="c-mo-configurar-un-proyecto-de-node-js"><strong>Cómo Configurar un Proyecto de Node.js</strong></h2><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/8dlICKn-tQw?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid1" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>Los pasos de abajo te ayudarán a configurar tu proyecto:</p><p>Abre la terminal o CMD y crea el directorio del proyecto:</p><pre><code class="language-bash">mkdir node_CLI_app</code></pre><p>Navega hacia el directorio:</p><pre><code class="language-bash">cd node_CLI_app</code></pre><p>Inicializa el proyecto:</p><pre><code class="language-bash">npm init	</code></pre><p>Traerá algunas preguntas. Presionar el botón Enter para cada indicación.</p><p>Un nuevo archivo (<code>package.json</code>) debería haber sido agregado en el directorio de tu proyecto. Usaremos el archivo para agregar código externo (módulo) al proyecto.<br><br>Agregar la siguiente línea antes de la llave (<code>}</code>) para habilitar import de ES6:</p><pre><code class="language-json">"type": "module"</code></pre><p>¡Eso completa la configuración del proyecto!</p><h2 id="c-mo-instalar-dependencias"><strong>Cómo Instalar Dependencias</strong></h2><p>Recordarás que el archivo <code>package.json</code> es para agregar código externo al proyecto. Este código externo también es llamado Dependencias, Módulos, o Paquetes. Está escrito por otros programadores (usualmente gratis) para ayudar a otros construir aplicaciones más rápido. Encontrarás muchos de estos en la <a href="https://www.npmjs.com/">página de npm</a>.</p><p>Necesitamos dos (2) paquetes para este proyecto: <a href="https://www.npmjs.com/package/inquirer">inquirer</a> y <a href="https://www.npmjs.com/package/uuid">uuid</a>. Te mostraré cómo puedes instalarlos en esta sección.</p><p>La instalación de paquetes sigue este patrón:</p><pre><code class="language-bash">npm install &lt;nombre_de_paquete&gt;</code></pre><p>Podemos instalar más de un paquete a la vez separando los nombres de los paquetes con un espacio:</p><pre><code class="language-bash">npm install &lt;nombre_de_paquete_1&gt; &lt;nombre_de_paquete_2&gt; &lt;nombre_de_paquete_3&gt;</code></pre><p>El comando <code>install</code> puede ser reemplazado con <code>i</code> para conveniencia.</p><p>Así que ejecuta el siguiente comando para instalar los paquetes:</p><pre><code class="language-bash">npm i inquirer uuid</code></pre><p>Tu archivo package.json debería tener las siguientes líneas de código agregadAs cuando la instalación esté completa:</p><pre><code class="language-json">
  "dependencies": {
    "inquirer": "^9.1.4",
    "uuid": "^9.0.0"
  }</code></pre><p>Los números de versión podrían diferir, pero no hay problema.</p><p>También notarás que un archivo (<code>package.lock.json</code>) y una carpeta (<code>node_modules</code>) han sido agregados. No tienes que preocuparte por ellos. Sólo ten en mente que te ayudan a gestionar código externo que agregamos.</p><p>¡Eso completa la instalación de dependencias!</p><h2 id="c-mo-crear-un-nuevo-archivo-desde-la-terminal"><strong>Cómo crear un Nuevo Archivo desde la Terminal</strong></h2><p>Puedes crear un archivo desde la terminal usando el siguiente comando:</p><ul><li>En Mac:</li></ul><pre><code class="language-bash">touch &lt;nombre_archivo&gt;</code></pre><ul><li>En Windows:</li></ul><pre><code class="language-bash">echo.&gt;&lt;nombre_archivo&gt;</code></pre><p>También puedes crear mas de un archivo a la vez separando los archivos con un espacio. Así es como generaremos los archivos para este proyecto:</p><pre><code class="language-bash">touch agregarDatos.js quitarDatos.js recuperarDatos.js actualizarDatos.js consultarBD.js bdArchivoChequeo.js</code></pre><p>Cada uno de esos archivos jugarán un rol único en la aplicación.</p><ul><li><code>agregarDatos.js</code> agrega datos a la Base de Datos. También fabrica el archivo de la Base de Datos si éste no existe.</li><li><code>quitarDatos.js</code> quita datos seleccionados.</li><li><code>recuperarDatos.js</code> busca todos los datos.</li><li><code>actualizarDatos.js</code> edita los datos.</li><li><code>consultarBD.js</code> chequea si la Base de Datos existe y ejecuta una función que se le pasa.</li><li><code>bdArchivoChequeo.js</code> confirma si el archivo de la Base de Datos ha sido creado.</li></ul><p>Hay un archivo más que no creamos: el archivo de la base de datos (<code>bd.json</code>). Lo auto-generaremos usando nuestro código. </p><h2 id="c-mo-comprobamos-si-un-archivo-existe"><strong>Cómo Comprobamos si un Archivo existe</strong></h2><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/V9dmEXCnY-8?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid2" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>Node.js provee un módulo integrado para manipular archivos – <a href="https://nodejs.org/api/fs.html">file system</a> (fs). Uno de los métodos que el módulo contiene es el método <code>existsSync</code>. Regresa <code>true</code> o <code>false</code> dependiendo en si el archivo ha sido creado. Lo usaré para verificar si el archivo <code>bd.json</code> está en el proyecto. Vea el código de abajo: </p><pre><code class="language-javascript">  import fs from "fs";
  import { exit } from "process";  
  
  if (fs.existsSync("bd.json")) {
    console.log("El archivo existe!");
    exit(1);
  }</code></pre><p>El método <code>exit</code> termina un proceso.</p><p>Así es como queremos hacer en el archivo <code>bdArchivoChequeo.js</code>. Sin embargo, queremos invertir el resultado agregando un <code>!</code> antes del método <code>fs.existsSync</code> así:</p><pre><code class="language-javascript">  import fs from "fs";
  import { exit } from "process";  
  
  if (!fs.existsSync("bd.json")) {
    console.log("El archivo no existe!");
    exit(1);
  }</code></pre><p>Esto será necesario cuando se construye otras funcionalidades como actualizar y eliminar datos.</p><p>Así que, ¿cómo ganarán acceso esos archivos a este código? Es a través de una estructura modular. Eso implica empaquetar este código y hacerlo accesible a través de otros archivos en el proyecto. El comando export lo hace posible:</p><pre><code class="language-javascript">import fs from "fs";
import { exit } from "process";

export default function dbFileCheck() {
  if (!fs.existsSync("bd.json")) {
    console.log("La Base de Datos está vacía. ¡Crea algún dato!");
    exit(1);
  }
}</code></pre><p>El código de arriba pone el código en una función (<code>bdArchivoChequeo</code>) y lo exporta usando el comando <code>export</code>. Esta función ahora puede ser importado y usado en otros archivos dentro de este proyecto.</p><p>Ten en cuenta que la palabra clave <code>default</code> es necesario para el primer export de un archivo.</p><h2 id="c-mo-consultar-la-base-de-datos"><strong>Cómo Consultar la Base de Datos</strong></h2><p>Otro método que <code>file system</code> tiene es el método <code>readFile</code>. Regresa el contenido de cualquier archivo que se le pase.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/ZmckWr9sH-w?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid3" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>El método <code>readFile</code> toma dos parámetros: el archivo a ser leído y una función callback que regresa el resultado de la operación.</p><p>Usaremos el siguiente código para recuperar datos desde nuestra base de datos:</p><pre><code class="language-javascript">import fs from "fs";

fs.readFile("bd.json", function (err, datos) {
  if (err) {
    console.log(err);
  }
  console.log(datos.toString());
});</code></pre><p>El código de arriba importa el módulo file system e intenta leer el archivo de la base de datos. Si hay un error, regresará el error. Si no hay errores, regresará los datos que obtuvo.</p><p>El método <code>.toString()</code> adjuntado a los datos regresados (<code>datos.toString()</code>) es porque los datos recuperados es del tipo <code>buffer</code> por defecto, lo cual no es legible. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074450995_Screenshot+2023-01-30+at+11.25.25.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074450995_Screenshot+2023-01-30+at+11.25.25" width="2654" height="107" loading="lazy"><figcaption>salida de buffer</figcaption></figure><p>Abre tu proyecto en un editor de código y pega ese código dentro del archivo <code>consultarBD.js</code>.</p><p>Ejecuta el comando de abajo para ver si está funcionando:</p><pre><code class="language-bash">node consultarBD</code></pre><p>El comando de arriba ejecutará cada código en el <code>consultarBD.js</code>. La extensión <code>.js</code> es opcional. Lo regresará de todas maneras.</p><p>El resultado de esa operación será un error porque no tenemos el archivo.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074558543_Screenshot+2023-01-30+at+11.28.47.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675074558543_Screenshot+2023-01-30+at+11.28.47" width="1515" height="344" loading="lazy"></figure><p>Puedes crear el archivo <code>bd.json</code>, agregar algún contenido, y verificar la salida.</p><p>Pero no queremos que nuestra app intente leer el archivo de la base de datos si este no ha sido generado. Así que utiliza el método <code>existsSync</code> para verificar si el archivo ha sido creado. Mira cómo lo uso en el código debajo:</p><pre><code class="language-javascript">    import fs from "fs";

    if (fs.existsSync("bd.json")) {
      fs.readFile("bd.json", function (err, datos) {
        if (err) {
          console.log(err);
        }
        console.log(datos.toString());
      });
    } else {
      console.log("¡Datos no disponibles!");
    }</code></pre><p>El código de arriba verífica si el archivo existe pasando el nombre del archivo (<code>bd.json</code>) al método <code>fs.existsSync</code>. Si es verdadero, entonces lee el archivo. Si es falso, regresa una cadena.</p><p>Ahora que tenemos ese código limpio, queremos hacerlo aún más robusto.</p><p>Siendo que estamos construyendo una aplicación CRUD, debemos tener acceso y hacer un seguimiento de los datos regresados. Para lograr eso, he introducido una nueva variable en el código de abajo:</p><pre><code class="language-javascript">    import fs from "fs";

    let info = [];
    if (fs.existsSync("bd.json")) {
      fs.readFile("bd.json", function (err, datos) {
        if (err) {
          console.log(err);
        }
        info = JSON.parse(datos.toString());
        console.log(info);
      });
    } else {
      console.log("¡Datos no disponibles!");
    }

</code></pre><p>El código de arriba ahora tiene una variable, <code>info</code>. Hace un seguimiento de los datos regresados. Pasé los datos a través del método <code>JSON.parse</code> para convertir los datos de una cadena a un arreglo.</p><p>Ahora podemos manipular el <code>info</code> según lo consideremos. Tenemos que exportar el código y aceptar una función para hacer esto posible. Esa función tomará la variable <code>info</code> como entrada y luego usarlo cuando sea requerido.</p><pre><code class="language-javascript">import fs from "fs";

export default async function consultarBD(funcionExterna) {
  try {
    let info = [];

    if (fs.existsSync("bd.json")) {
      await fs.readFile("bd.json", function (err, datos) {
        info = JSON.parse(datos.toString());
        console.log(info);

        if (err) {
          console.log(err);
          return;
        }

        if (funcionExterna &amp;&amp; !err) {
          funcionExterna(info);
          return;
        }
      });
    } else {
      if (funcionExterna) {
        funcionExterna(info);
        return;
      }
    }
  } catch (error) {
    console.error(`Algo ocurrió: ${error.message}`);
  }
}</code></pre><p>Este código toma una función y lo ejecuta solamente si no hay errores. Sin embargo, habrá una excepción – cuando se agreguen datos. En ese caso, la base de datos será creado.</p><p>El bloque <code>try...catch...</code> ayuda a recoger errores, y las palabras claves <code>async</code> <code>await</code> son usados cuando se ejecuta código que tomará mucho tiempo en correr.</p><p>El <code>consultarBD.js</code> ya no regresará ninguna salida cuando ejecutemos el comando <code>node consultarBD</code>. Pero está bien. Lo dispararemos desde otros archivos.</p><h2 id="c-mo-agregar-datos-a-un-archivo"><strong>Cómo Agregar Datos a un Archivo</strong></h2><p>En esta sección, te enseñaré cómo agregar datos al almacén. El archivo para esta sección es el archivo <code>agregarDatos.js</code>.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/vi0unBmidkE?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid4" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>Empezaremos por importar todos los módulos necesarios:</p><pre><code class="language-javascript">import inquirer from "inquirer";
import fs from "fs";
import { v4 as uuidv4 } from "uuid";
import consultarBD from "./consultarBD.js";</code></pre><p>Siguiente, crea el boilerplate para la función:</p><pre><code class="language-javascript">export default async function agregarDatos(info) {
  try {
    
  } catch (error) {
    console.log("¡Algo salió mal!", error);
  }
}
</code></pre><p>Esto es similar a lo que hemos hecho antes de ahora. Todo el código que escribiríamos luego irá dentro del bloque <code>try...</code>. El arreglo <code>info</code> pasado a la función viene del archivo <code>consultarBD</code>.</p><p>La primera cosa por hacer en el bloque <code>try...</code> es recolectar los datos que serán almacenados. Usaremos <code>inquirer</code> para hacer eso con el código de abajo:</p><pre><code class="language-javascript">const respuestas = await inquirer.prompt([
      {
        type: "input",
        name: "nombre",
        message: "¿Cómo te llamas?",
      },
      {
        type: "number",
        name: "telefono",
        message: "¿Cuál es tu teléfono?",
      },
      {
        type: "list",
        name: "edad",
        message: "¿Eres un adulto?",
        choices: [
          { name: "S", value: "Adulto" },
          { name: "N", value: "Menor" },
        ],
      },
    ]);</code></pre><p>El paquete <code>inquirer</code> ayuda en la construcción de interfaces de línea de comandos interactivos. Contiene un método llamado <code>prompt</code> usado para pedir datos. Toma un arreglo de preguntas en formato de objeto. Cada objeto debe tener las claves <code>name</code>, <code>type</code> y <code>message</code>.</p><p>La clave <code>choices</code> es opcional. Es usado cuando hay una lista de opciones.</p><p>Así que el código de arriba recolecta tres (3) entradas (nombre, teléfono, y edad) y los almacena en una variable llamada <code>respuestas</code>.</p><p>Luego, asignamos a este conjunto de entradas un ID único llamando la función <code>uuidv4()</code> y empujar todo dentro del arreglo <code>info</code>: </p><pre><code class="language-javascript">    const datos = {
      id: uuidv4(),
      nombre: answers.nombre,
      telefono: answers.telefono,
      edad: answers.edad,
    };
    info.push(datos);</code></pre><p>Finalmente, verificamos si el archivo de la base de datos existe. Actualizaremos la base de datos con los nuevos datos si el archivo ha sido creado o crearlo y agregar los nuevos datos si es falso.</p><pre><code class="language-javascript">    if (fs.existsSync("bd.json")) {
      crearDetalles(info);
    } else {
      fs.appendFile("bd.json", "[]", (err) =&gt; {
        if (err) {
          console.log("No se pudo crear bd.json", err);
          return;
        }
        crearDetalles(info);
      });
    }</code></pre><p>La función <code>crearDetalles</code>será usado para sobreescribir los datos de la base de datos. Lo crearé en un momento.</p><p>En el bloque <code>else</code> (si el archivo no existe), creé el archivo usando el método <code>appendFile</code> del sistema. Este método es usado para crear un archivo si no está allí todavía y agregar o adjuntar datos al final del archivo. </p><p>Estoy adjuntando <code>[]</code> al archivo. Así que el nuevo archivo creado tendrá sólo <code>[]</code> dentro. Llamé a la función <code>crearDetalles</code> luego para agregar los datos coleccionados desde el CLI.</p><p>Por favor escribe el siguiente código para la función crearDetalles la función de agregarDatos abajo:</p><pre><code class="language-javascript">async function crearDetalles(info) {
  await fs.writeFile("bd.json", JSON.stringify(info), function (err) {
    if (err) {
      console.log(err);
    }
    console.log("¡Guardado!");
  });
}</code></pre><p>Esta función usa el método <code>writeFile</code> del sistema de archivos para sobreescribir la base de datos con datos actuales. Estoy usando <code>JSON.stringify</code> para convertir la variable <code>info</code> a una cadena porque es el formato aceptable cuando se escribe a un archivo. Eso también explica por qué usé <code>JSON.parse</code> para convertirlo al tipo original cuando lo recuperé en la sección previa.</p><p><code>writeFile</code> es diferente desde <code>appendFile</code> porque <code>writeFile</code> sobreescribe un archivo mientras que <code>appendFile</code> agrega al contenido existente. Son similares en tanto que ambos métodos creará el archivo si este no ha sido creado.</p><p>Lo último para hacer en este archivo es invocar o llamar a la función. La manera de hacerlo es escribir su nombre seguido de abrir y cerrar paréntesis de esta manera:</p><pre><code class="language-javascript">agregarDatos();</code></pre><p>Esto podría funcionar bien, pero no haría lo que queremos. Necesitamos pasar la función como un argumento dentro de <code>consultarBD</code> de esta manera:</p><pre><code class="language-javascript">consultarBD(agregarDatos);</code></pre><p>Ahora, el <code>agregarDatos</code> será capaz de comunicarse con la función <code>consultarBD</code>.</p><h2 id="c-mo-testear-el-archivo-agregardatos"><strong>Cómo Testear el Archivo <code>agregarDatos</code></strong></h2><p>Ejecuta el comando de abajo para testear si el archivo <code>agregarDatos</code> funciona como se espera:</p><pre><code class="language-bash">node agregarDatos</code></pre><p>Te mostrará mensajes para responder. Completa las respuestas. Después de eso, tu pantalla debería parecerse como el mío:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675241012883_Screenshot+2023-02-01+at+09.42.57.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675241012883_Screenshot+2023-02-01+at+09.42.57" width="1057" height="236" loading="lazy"><figcaption>salida de agregarDatos</figcaption></figure><p>También debería haber auto-generado un archivo <code>db.json</code> con los datos que agregaste.</p><p>Y eso es todo para el archivo <code>agregarDatos</code>!</p><h2 id="c-mo-recuperar-datos"><strong>Cómo Recuperar Datos</strong></h2><p>Esta sección te muestra cómo obtener el contenido de la base de datos. Todo lo que necesitas para lograr esta funcionalidad es el código de abajo:</p><pre><code class="language-javascript">import consultarBD from "./consultaBD.js";

consultarBD();</code></pre><p>Lo que el código hace es importar la función <code>consultarBD</code> e invocarla. Pega el código en el archivo <code>recuperarDatos.js</code> y ejecuta el archivo con:</p><pre><code class="language-bash">node recuperarDatos</code></pre><p>Regresará una salida similar a esto:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675319554801_Screenshot+2023-02-02+at+07.29.43.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675319554801_Screenshot+2023-02-02+at+07.29.43" width="1162" height="389" loading="lazy"><figcaption>salida de recuperarDatos.js</figcaption></figure><p>Te preguntarás: ¿por qué no llamé esta función en el archivo <code>consultarBD</code>? La razón es que el archivo realiza más que sólo recuperar datos. Llamar la función <code>consultarBD</code> en su archivo alterará el resultado de los otros archivos.</p><h2 id="c-mo-editar-datos"><strong>Cómo Editar Datos</strong></h2><p>Esta sección ahora se enfocará en cómo actualizar datos. El patrón a seguir aquí es:</p><ul><li>Recoger el ID del usuario.</li><li>Buscar al usuario.</li><li>Regresar los datos del usuario si el usuario existe, y establecerlo como la opción por defecto.</li><li>Pedir por información actualizada. El valor inicial será guardada si el usuario presiona la tecla <code>Enter</code>.</li><li>Finalmente, sobrescribir la base de datos con la información actualizada.</li></ul><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/UmshAmmU-44?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid5" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>Hagámoslo...</p><p>Navega dentro del archivo <code>actualizarDatos.js</code> y pega el siguiente código:</p><pre><code class="language-javascript">import inquirer from "inquirer";
import fs from "fs";
import consultarBD from "./consultarBD.js";
import bdArchivoChequeo from "./bdArchivoChequeo.js";

export default async function actualizarDatos(info) {
  bdArchivoChequeo();

  try {
    
  } catch (error) {
    console.log("Algo salió mal!", error);
  }
}</code></pre><p>Este es el código para la función <code>actualizarDatos</code>. Lo nuevo aquí es la función <code>bdArchivoChequeo</code> (hecho hace unos momentos atrás) para terminar una operación si la base de datos no ha sido creada.</p><p>El resto del código estará dentro del bloque <code>try...</code>.</p><p>Lo primero es recoger el ID del usuario con este código:</p><pre><code class="language-javascript">    const respuestas = await inquirer.prompt([
      {
        type: "input",
        name: "registroID",
        message: "Ingresa Registro ID",
      },
    ]);</code></pre><p>El segundo es buscar al usuario:</p><pre><code class="language-javascript">    let actual;

    info.forEach((elemento) =&gt; {
      if (elemento.id === respuestas.registroID) {
        actual = elemento;

        actualizarDetalles(actual, info);
      }
    });</code></pre><p>El código de arriba busca a través de los usuarios (<code>info</code>) y coloca al usuario hallado en la variable <code>actual</code>. Finalmente, la función <code>actualizarDetalles</code> es llamado para recoger la información actualizada y sobrescribir la base de datos con los nuevos datos.</p><h3 id="c-mo-construir-la-funci-n-actualizardetalles"><strong>Cómo construir la función <code>actualizarDetalles</code></strong></h3><p>Esta parte mostrará cómo hacer un seguimiento de los datos iniciales de un usuario mientras se recogen nuevos datos. Actualizará la base de datos con los nuevos datos después.</p><p>El siguiente código es la estructura para la función:</p><pre><code class="language-javascript">async function actualizarDetalles(actual, info) {
  try {
    
  } catch (error) {
    console.log("¡Algo salió mal!", error);
  }
}</code></pre><p>Este código va debajo de la operación <code>actualizarDatos</code>.</p><p>El código de abajo va dentro del bloque <code>try...</code>. Es para recoger información actualizada del usuario.</p><pre><code class="language-javascript">  const devoluciones = await inquirer.prompt([
      {
        type: "input",
        default: actual.nombre,
        name: "nombre",
        message: "¿Cuál es tu nombre?",
      },
      {
        type: "number",
        default: actual.telefono,
        name: "telefono",
        message: "¿Cuál es tu teléfono?",
      },
      {
        type: "list",
        default: actual.edad,
        name: "edad",
        message: "¿Eres un adulto?",
        choices: [
          { name: "S", value: "Adulto" },
          { name: "N", value: "Menor" },
        ],
      },
    ]);</code></pre><p>La clave <code>default</code> es nuevo. Retiene dato que será usado si el usuario no provee una. Hace un seguimiento de los datos actuales del usuario para este código. Así, el usuario puede presionar el botón <code>Enter</code> en vez de ingresar el valor anterior otra vez.</p><p>Los detalles del usuario debería ser actualizado respectivamente usando este código:</p><pre><code class="language-javascript">    actual.nombre = devoluciones.nombre;
    actual.telefono = devoluciones.telefono;
    actual.edad = devoluciones.edad;</code></pre><p>Finalmente, sobrescribir la base de datos con el nuevo valor:</p><pre><code class="language-javascript">await fs.writeFile("bd.json", JSON.stringify(info), function (err) {
      if (err) {
        console.log(err);
      }
      console.log("actualizado");
    });</code></pre><p>Llama la función <code>actualizarDatos</code> para traer todo junto:</p><pre><code class="language-javascript">consultarBD(acutalizarDatos)</code></pre><h3 id="c-mo-testear-el-archivo-actualizardatos"><strong>Cómo testear el archivo <code>actualizarDatos</code></strong></h3><p>Ejecuta el comando debajo para ver cómo actúa la función <code>actualizarDatos</code>:</p><pre><code class="language-bash">node actualizarDatos</code></pre><p>Te mostrará un mensaje pidiendo un ID. Ingresa el ID de cualquier registro en la base de datos.</p><p>Luego te mostrará un mensaje por información actualizada sobre el usuario. Rellena la información y presiona <code>Enter</code> por cualquier detalle que no necesite una actualización. La terminal debería lucir así al final:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675324018105_Screenshot+2023-02-02+at+08.45.07.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675324018105_Screenshot+2023-02-02+at+08.45.07" width="1334" height="260" loading="lazy"><figcaption>salida de actualizarDatos</figcaption></figure><p>Eso concluye para el archivo <code>actualizarDatos</code>. Los registros pueden ser actualizados ahora.</p><h2 id="c-mo-eliminar-datos"><strong>Cómo Eliminar Datos</strong></h2><p>Una aplicación CRUD no puede ser completado sin la parte de DELETE (ELIMINAR). Ese será el enfoque aquí. Tomará un poco de las secciones anteriores. Así no será mucho para captar.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.90444444444445%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/JptWEtAtOeA?list=PLOvIwkWvHysNC83IAQZrxgkUZgA1k5WZE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid6" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 539.312px;"></iframe>
          </div>
        </div>
      </figure><p>Empezarás por escribir el siguiente código en el archivo <code>removerDatos.js</code>:</p><pre><code class="language-javascript">import inquirer from "inquirer";
import fs from "fs";
import consultarBD from "./consultarBD.js";
import bdArchivoChequeo from "./bdArchivoChequeo.js";

export default async function removerDatos(info) {
  bdArchivoChequeo();

  try {
    const respuestas = await inquirer.prompt([
      {
        type: "input",
        name: "registroID",
        message: "Ingresa el ID del Registro",
      },
    ]);

    let datosRestantes = [];
    info.forEach((elemento) =&gt; {
      if (elemento.id !== respuestas.registroID) {
        datosRestantes.push(elemento);
      }
    });

    fs.writeFile("bd.json", JSON.stringify(datosRestantes), function (err) {
      if (err) {
        console.log(err);
      }
      console.log("¡Eliminado!");
    });
  } catch (error) {
    console.log("¡Algo salió mal!", error);
  }
}
</code></pre><p>Primero, el código de arriba recoge un ID.</p><p>Luego, usa el ID para buscar los datos de la base de datos y retiene solamente los datos con un ID distinto en el arreglo <code>datosRestantes</code>.<br><br>Finalmente, sobrescribe la base de datos con los datos actualizados.</p><p>Llama la función removerDatos al final para poner todo junto de esta manera:</p><pre><code class="language-javascript">consultarBD(removerDatos)</code></pre><p>Ahora intenta testear el archivo usando este comando:</p><pre><code class="language-bash">node removerDatos</code></pre><p>Esta es mi salida:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://paper-attachments.dropboxusercontent.com/s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675329363353_Screenshot+2023-02-02+at+10.15.12.png" class="kg-image" alt="s_D592C23061BDAFBA9E611AEDC8048F685A5679FCF2C57746CD5AE80A3DAD15B0_1675329363353_Screenshot+2023-02-02+at+10.15.12" width="1309" height="109" loading="lazy"><figcaption>salida de removerDatos</figcaption></figure><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>La mejor manera para aprender a programar es haciendo. Y algunos de los mejores proyectos es construir aplicaciones CRUD porque cubren lo básico de lo que un proyecto profesional requiere. Esto es lo que he hecho en este tutorial.</p><p>Te he enseñado lo básico de Node.js construyendo una aplicación que crea, lee, actualiza, y elimina registros. Cubrí conceptos tales como leer archivos, escribir a archivos, bucles, sentencias condicionales, módulos y operaciones del CLI.</p><p>Todos los archivos para este tutorial están en <a href="https://github.com/EBEREGIT/Nodejs_CLI_app">GitHub</a>.</p><p>Ahora tienes todo lo básico necesario para empezar a construir aplicaciones usando Node.js. Algo que me gustaría que intentaras es actualizar o eliminar más de un registro a la vez.</p><p>Tengo otros tutoriales en Node.js, y te sugiero que los sigas en este orden para hacer crecer tus habilidades:</p><ul><li>Cómo Construir un Servidor Seguro con Node.js y Express y Subir Imágenes con Cloudinary</li><li>Cómo Construir y Desplegar una App Backend con Express, Postgres, Github, y Heroku</li><li>Cómo Construir una App de Autenticación Full-Stack con React, Express, MongoDB, Heroku y Netlify</li></ul><p>¡Feliz día construyendo!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Introducción a Mongoose para MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ Mongoose es una biblioteca de modelado de datos orientada a objetos (ODM [https://www.mongodb.com/tools/mongoose]) para MongoDB y Node.js. Administra las relaciones entre los datos, proporciona validación de esquemas y se utiliza para traducir entre objetos en el código y la representación de esos objetos en MongoDB. Mapeo de objetos entre Node ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/introduccion-a-mongoose-para-mongodb/</link>
                <guid isPermaLink="false">6402a06f2154fe0736d634a5</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrés  Torres ]]>
                </dc:creator>
                <pubDate>Wed, 15 Mar 2023 13:51:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/03/MONGODB.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/introduction-to-mongoose-for-mongodb-d2a7aa593c57/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Introduction to Mongoose for MongoDB</a>
      </p><p>Mongoose es una biblioteca de modelado de datos orientada a objetos (<a href="https://www.mongodb.com/tools/mongoose">ODM</a>) para MongoDB y Node.js. Administra las relaciones entre los datos, proporciona validación de esquemas y se utiliza para traducir entre objetos en el código y la representación de esos objetos en MongoDB.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/03/image.png" class="kg-image" alt="image" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/03/image.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2023/03/image.png 800w" sizes="(min-width: 720px) 720px" width="800" height="390" loading="lazy"><figcaption>Mapeo de objetos entre Node y MongoDB administrado a través de Mongoose</figcaption></figure><p>MongoDB es una base de datos de documentos NoSQL sin esquema. Significa que puede almacenar documentos JSON en él, y la estructura de estos documentos puede variar, &nbsp;porque que no se aplica como las bases de datos SQL. Esta es una de las ventajas de usar NoSQL, ya que acelera el desarrollo de aplicaciones y reduce la complejidad de las implementaciones.</p><p>A continuación se muestra un ejemplo de cómo se almacenan los datos en Mongo vs. SQL Database:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/03/image-1.png" class="kg-image" alt="image-1" width="594" height="956" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/03/image-2.png" class="kg-image" alt="image-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/03/image-2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2023/03/image-2.png 682w" width="682" height="931" loading="lazy"><figcaption>Documentos NoSQL vs. Tablas Relacionales en SQL</figcaption></figure><h2 id="terminolog-as">Terminologías</h2><h3 id="colecciones">Colecciones</h3><p>Las "colecciones" en Mongo son equivalentes a las tablas en las bases de datos relacionales. Pueden contener varios documentos JSON.</p><h3 id="documentos">Documentos</h3><p>Los "documentos" son equivalentes a registros o filas de datos en SQL. Si bien una fila de SQL puede hacer referencia a datos en otras tablas, los documentos de Mongo generalmente combinan eso en un documento.</p><h3 id="campos">Campos</h3><p>Los "campos" o atributos son similares a las columnas de una tabla SQL.</p><h3 id="esquema">Esquema</h3><p>Si bien Mongo no tiene esquema, SQL define un esquema a través de la definición de la tabla. Un "esquema" de Mongoose es una estructura de datos del documento (o la forma del documento) que se aplica a través de la capa de aplicación.</p><h3 id="modelos">Modelos</h3><p>Los "modelos" son constructores de orden superior que toman un esquema y crean una instancia de un documento equivalente a los registros en una base de datos relacional.</p><p><strong>Ejemplo</strong><br>Aquí hay un pequeño fragmento de código para ilustrar parte de la terminología anterior:</p><pre><code class="language-js">const puppySchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  age: Number
});

const Puppy = mongoose.model('Puppy', puppySchema);
</code></pre><p>En el código anterior, <code>puppySchema</code> se define la forma del documento. Este tiene dos campos nombre y edad, <code>name</code> ,<code>age</code>.</p><p>Usamos <code>SchemaType</code> para <code>name</code> como un <code>String</code> mientras que para la variable <code>age</code> empleamos <code>Number</code> (debido a que la edad denota un número específico). Observa que cuando definimos <code>SchemaType</code> para un campo, por medio de usar un objeto con la propiedad &nbsp;<code>type</code> igual a la de <code>name</code>. O bien, puedes aplicar <code>SchemaType</code> directamente al campo <code>age</code>.</p><p>También observa que <code>SchemaType</code> para <code>name</code> tiene la opción <code>required</code> ajustada a un valor booleano <code>true</code>. Para usar opciones como <code>required</code> y <code>lowercase</code> en un campo, necesitas emplear un objeto específico que te ayude a definir el <code>SchemaType</code>.</p><p>En la parte inferior del fragmento, <code>puppySchema</code> se compila en un modelo llamado &nbsp;<code>Puppy</code>, que luego se puede usar para construir documentos en una aplicación.</p><h2 id="empezando">Empezando</h2><h3 id="instalaci-n-de-mongodb">Instalación de Mongodb</h3><p>Antes de comenzar, configuremos Mongo. Puedes elegir entre una de las siguientes opciones (estamos usando la opción n.º 1 para este artículo):</p><p>1.Descarga la versión más apropiada de MongoDB version para tu sistema operativo del <a href="https://www.mongodb.com/download-center#community" rel="noopener"> Website</a> de MongoDB, y sigue las correspondientes instrucciones de instalación.</p><p>2.<a href="http://docs.mlab.com/" rel="noopener">Crea una base de datos sandbox </a> gratuita mediante una suscripción en mLab.</p><p>3. <a href="https://docs.docker.com/samples/library/mongo/" rel="noopener">Instala Mongo usando Docker</a> si prefieres usar Docker.</p><p>Naveguemos a través de algunos de los conceptos básicos de Mongoose implementando un modelo que representa datos para una libreta de direcciones simplificada.<br>Estoy usando Visual Studio Code, Node 8.9 y NPM 5.6. Enciende tu IDE favorito, crea un proyecto en blanco y ¡comencemos! Usaremos la sintaxis ES6 limitada en Node, por lo que no configuraremos Babel.</p><h4 id="npm-install"><strong>NPM Install</strong></h4><p>Vayamos al archivo del proyecto para darle un inicio.</p><pre><code class="language-bash">npm init -y</code></pre><p>Instalamos Mongoose junto con una biblioteca de validación con el siguiente comando:</p><pre><code class="language-bash">npm install mongoose validator</code></pre><p>El comendo anterior instalará la última versión de las bibliotecas. <strong>La sintaxis de Mongoose en este artículo es específica desde Mongoose v5 en adelante.</strong></p><h4 id="conecci-n-a-la-base-de-datos"><strong>Conección a la Base de Datos</strong></h4><p>Crea un archivo &nbsp;<code>./src/database.js</code><strong><strong><em><em> </em></em></strong><em> </em></strong>bajo la raíz del proyecto.</p><p>A continuación, añadiremos una clase simple con un método que se conecta a la base de datos.<br><strong>La cadena de conexión variará según los detalles de tu instalación.</strong></p><pre><code class="language-js">let mongoose = require('mongoose');

const server = '127.0.0.1:27017'; // REPLACE WITH YOUR DB SERVER
const database = 'fcc-Mail';      // REPLACE WITH YOUR DB NAME

class Database {
  constructor() {
    this._connect()
  }
  
_connect() {
     mongoose.connect(`mongodb://${server}/${database}`)
       .then(() =&gt; {
         console.log('Database connection successful')
       })
       .catch(err =&gt; {
         console.error('Database connection error')
       })
  }
}

module.exports = new Database()</code></pre><p>La llamada <code>require(‘mongoose’)</code><strong><strong> </strong></strong>retorna un objeto <em>Singleton</em>. Lo que significa que la primera vez que llames <code>require(‘mongoose’)</code>, está creando una instancia de la clase Mongoose y devolviéndola. En llamadas posteriores, devolverá la misma instancia que se creó y se le devolvió la primera vez debido a cómo funciona la importación/exportación de módulos en ES6.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/0*RvVsD_byUakUzuCj." class="kg-image" alt="0*RvVsD_byUakUzuCj" width="800" height="339" loading="lazy"><figcaption>Module import/require work-flow</figcaption></figure><p>De manera similar, hemos convertido nuestra clase de base de datos en un <em>singleton</em> al devolver una instancia de la clase en la declaración <code>module.exports</code> porque solo necesitamos una única conexión a la base de datos.</p><p>ES6 hace que sea muy fácil para nosotros crear un patrón <em>singleton</em> (instancia única) debido a cómo funciona el cargador de módulos al almacenar en caché la respuesta de un archivo previamente importado.</p><h3 id="esquema-mongoose-vs-modelo"><strong>Esquema Mongoose vs. Modelo</strong></h3><p>Un modelo Mongoose es un contenedor en el esquema Mongoose. <strong>Un esquema Mongoose define la estructura del documento</strong>, valores predeterminados, validadores, etc., <strong>mientras que un modelo Mongoose proporciona una interfaz </strong>a la base de datos para crear, consultar, actualizar, eliminar registros, etc.</p><p>La creación de un modelo Mongoose consta principalmente de tres partes:</p><h4 id="1-referenciando-mongoose"><strong><strong><strong>1. Referenc</strong>iando <strong>Mongoose</strong></strong></strong></h4><pre><code class="language-js">let mongoose = require('mongoose')</code></pre><p>Esta referencia será la misma que se devolvió cuando nos conectamos a la base de datos, lo que significa que las definiciones de esquema y modelo no necesitarán conectarse explícitamente a la base de datos.</p><h4 id="2-definiendo-el-esquema"><strong>2. Definiendo el esquema </strong></h4><p><strong>Un esquema define las propiedades del documento a través de un objeto</strong> donde el <strong>nombre de la clave</strong> corresponde al <strong>nombre de la propiedad</strong> en la colección.</p><pre><code class="language-js">let emailSchema = new mongoose.Schema({
  email: String
})</code></pre><p>Aquí definimos una <strong>propiedad llamada correo electrónico con un tipo de esquema <em>String</em></strong> que se asigna a un validador interno que se activará cuando el modelo se guarde en la base de datos. Fallará si el tipo de datos del valor no es un <em>String</em>.</p><p>A nivel general, los siguientes tipos de esquemas están permitidos en Mogoose:</p><ul><li>Array (Arreglo)</li><li>Boolean (Booleano)</li><li>Buffer</li><li>Date (Fecha)</li><li>Mixto (Genérico/ tipo de dato flexible)</li><li>Number (Número)</li><li>ObjectId</li><li>String</li></ul><p>Mixed y ObjectId están definidas mediante <code>require(‘mongoose’).Schema.Types</code>.</p><h4 id="3-exportando-un-modelo"><strong><strong><strong>3. Ex</strong>portando un modelo</strong></strong></h4><p>Necesitamos llamar al constructor del modelo en la instancia de Mongoose y pasarle el nombre de la colección y una referencia a la definición del esquema.</p><pre><code class="language-js">module.exports = mongoose.model('Email', emailSchema)</code></pre><p>Resumamos el código de arriba en <code>./src/models/email.js</code><strong><strong> </strong></strong>. Esto a fin de definir los contenidos de un modelo de email básico:</p><pre><code class="language-js">let mongoose = require('mongoose')

let emailSchema = new mongoose.Schema({
  email: String
})

module.exports = mongoose.model('Email', emailSchema)</code></pre><p>La definición de un esquema debe ser simple, pero su complejidad generalmente se basa en los requisitos de la aplicación. Los esquemas se pueden reutilizar y también pueden contener varios esquemas secundarios. </p><p>En el ejemplo anterior, el valor de la propiedad de correo electrónico es un tipo de valor simple. Sin embargo, también puede ser un tipo de objeto con propiedades adicionales.<br>Podemos crear una instancia del modelo que definimos anteriormente y llenarlo usando la siguiente sintaxis:</p><pre><code class="language-js">let EmailModel = require('./email')

let msg = new EmailModel({
  email: 'ada.lovelace@gmail.com'
})</code></pre><p>Mejoremos el esquema de correo electrónico para hacer que la propiedad de correo electrónico sea un campo único y obligatorio y convertir el valor a minúsculas antes de guardarlo. También podemos<strong> agregar una función de validación que garantizará que el valor sea una dirección de correo electrónico válida</strong>. Haremos referencia y usaremos la biblioteca de validación instalada anteriormente.</p><pre><code class="language-js">let mongoose = require('mongoose')
let validator = require('validator')

let emailSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    validate: (value) =&gt; {
      return validator.isEmail(value)
    }
  }
})

module.exports = mongoose.model('Email', emailSchema)</code></pre><h2 id="operaciones-b-sicas">Operaciones Básicas</h2><p>Mongoose tiene una API flexible y proporciona muchas formas de realizar una tarea. No nos centraremos en las variaciones porque están fuera del alcance de este artículo, pero recuerde que la mayoría de las operaciones se pueden realizar de más de una forma, ya sea sintácticamente o mediante la arquitectura de la aplicación.</p><h3 id="crear-un-registro">Crear un registro</h3><p>Vamos a crear una instancia del modelo de correo electrónico y guardarlo en la base de datos:</p><pre><code>let EmailModel = require('./email')

let msg = new EmailModel({
  email: 'ADA.LOVELACE@GMAIL.COM'
})

msg.save()
   .then(doc =&gt; {
     console.log(doc)
   })
   .catch(err =&gt; {
     console.error(err)
   })</code></pre><p>El resultado es un documento que se devuelve al guardar correctamente:</p><pre><code class="language-json">{ 
  _id: 5a78fe3e2f44ba8f85a2409a,
  email: 'ada.lovelace@gmail.com',
  __v: 0 
}</code></pre><p>Se devuelven los siguientes campos (los campos internos tienen un prefijo con un guión bajo):</p><ol><li>El campo <code>_id</code> es generado automáticamente por Mongo y es una clave principal de la colección. Su valor es un identificador único para el documento.</li><li>El valor del campo <code>email</code> es devuelto. Observa que está en minúsculas porque especificamos el <code>lowercase:true</code> atribuido en el esquema.</li><li><code>__v</code> es la propiedad versionKey establecida en cada documento cuando Mongoose lo crea por primera vez. Su valor contiene la revisión interna del documento.</li></ol><p>Si intentas repetir la operación de guardar anterior, obtendrás un error porque hemos especificado que el campo de correo electrónico debe ser único.</p><h3 id="obtener-un-registro">Obtener un registro</h3><p>Intentemos recuperar el registro que guardamos en la base de datos anteriormente. La clase modelo expone varios métodos estáticos y de instancia para realizar operaciones en la base de datos. Ahora intentaremos encontrar el registro que creamos previamente usando el método de búsqueda y pasar el correo electrónico como término de búsqueda.</p><pre><code>EmailModel
  .find({
    email: 'ada.lovelace@gmail.com'   // search query
  })
  .then(doc =&gt; {
    console.log(doc)
  })
  .catch(err =&gt; {
    console.error(err)
  })</code></pre><p>El documento devuelto será similar al que se mostró cuando creamos el registro:</p><pre><code class="language-json">{ 
  _id: 5a78fe3e2f44ba8f85a2409a,
  email: 'ada.lovelace@gmail.com',
  __v: 0 
}</code></pre><h3 id="actualizar-registro">Actualizar Registro</h3><p>Modifiquemos el registro anterior cambiando la dirección de correo electrónico y agregando otro campo, todo en una sola operación. Por motivos de rendimiento, Mongoose no devolverá el documento actualizado, por lo que debemos pasar un parámetro adicional para solicitarlo:</p><pre><code class="language-js">EmailModel
  .findOneAndUpdate(
    {
      email: 'ada.lovelace@gmail.com'  // search query
    }, 
    {
      email: 'theoutlander@live.com'   // field:values to update
    },
    {
      new: true,                       // return updated doc
      runValidators: true              // validate before update
    })
  .then(doc =&gt; {
    console.log(doc)
  })
  .catch(err =&gt; {
    console.error(err)
  })</code></pre><p>El documento devuelto contendrá el correo electrónico actualizado:</p><pre><code class="language-json">{ 
  _id: 5a78fe3e2f44ba8f85a2409a,
  email: 'theoutlander@live.com',
  __v: 0 
}</code></pre><h3 id="borrar-registro-record">Borrar registro Record</h3><p>Usaremos <code>findOneAndRemove</code> para borrar un registro. Este retorna el documento original que ha sido removido:</p><pre><code class="language-js">EmailModel
  .findOneAndRemove({
    email: 'theoutlander@live.com'
  })
  .then(response =&gt; {
    console.log(response)
  })
  .catch(err =&gt; {
    console.error(err)
  })</code></pre><h3 id="ayudas"><strong>Ayudas</strong></h3><p>Hemos analizado algunas de las funciones básicas anteriores conocidas como operaciones CRUD (Crear, Leer, Actualizar, Eliminar), pero Mongoose también brinda la capacidad de configurar varios tipos de métodos auxiliares y propiedades. Estos se pueden utilizar para simplificar aún más el trabajo con datos.</p><p>Creemos un esquema <code>./src/models/user.js</code> con los campos<code>firstName</code> y <code>lastName</code>:</p><pre><code class="language-js">let mongoose = require('mongoose')

let userSchema = new mongoose.Schema({
  firstName: String,
  lastName: String
})

module.exports = mongoose.model('User', userSchema)</code></pre><h3 id="propiedad-virtual">Propiedad Virtual</h3><p>Una <a href="https://mongoosejs.com/docs/tutorials/virtuals.html">propiedad virtual </a>no se conserva en la base de datos. Podemos agregarlo a nuestro esquema como ayuda para obtener y establecer valores.</p><p>Creemos una propiedad virtual <code>fullName</code> que puede ser empleada para asignar valores en <code>firstName</code> y <code>lastName</code> y recuperarlos como un valor combinado cuando se lea:</p><pre><code class="language-js">userSchema.virtual('fullName').get(function() {
  return this.firstName + ' ' + this.lastName
})

userSchema.virtual('fullName').set(function(name) {
  let str = name.split(' ')
  
  this.firstName = str[0]
  this.lastName = str[1]
})</code></pre><p>Las devoluciones de llamada para <em>get</em> y <em>set</em> (en el código) deben usar la palabra clave <em>function</em>, ya que necesitamos acceder al modelo a través de la palabra clave <code>this</code>. El uso de funciones de flecha gruesa cambiará a lo que <code>this</code>se refiere.</p><p>Ahora podemos definir <code>firstName</code> y <code>lastName</code> asignándole un valor a <code>fullName</code>:</p><pre><code class="language-js">let model = new UserModel()

model.fullName = 'Thomas Anderson'

console.log(model.toJSON())  // Output model fields as JSON
console.log()
console.log(model.fullName)  // Output the full name</code></pre><p>El resultado del código anterior es el siguiente:</p><pre><code class="language-bash">{ _id: 5a7a4248550ebb9fafd898cf,
  firstName: 'Thomas',
  lastName: 'Anderson' }
  
Thomas Anderson</code></pre><h3 id="m-todos-de-instancia">Métodos de instancia</h3><p>Podemos crear métodos auxiliares personalizados en el esquema y acceder a ellos a través de la instancia del modelo. Estos métodos tendrán acceso al objeto modelo y se pueden usar de manera bastante creativa. Por ejemplo, podríamos crear un método para encontrar a todas las personas que tienen el mismo nombre que la instancia actual.</p><p>En este ejemplo, vamos a crear una función para devolver las iniciales del usuario actual. Agreguemos un método auxiliar personalizado llamado <code>getInitials</code> al esquema:</p><pre><code class="language-js">userSchema.methods.getInitials = function() {
  return this.firstName[0] + this.lastName[0]
}</code></pre><p>Se podrá acceder a este método a través de una instancia de modelo:</p><pre><code class="language-js">let model = new UserModel({
  firstName: 'Thomas',
  lastName: 'Anderson'
})

let initials = model.getInitials()

console.log(initials) // This will output: TA</code></pre><h3 id="m-todos-est-ticos">Métodos estáticos</h3><p>Similar a los métodos de instancia, podemos crear métodos estáticos en el esquema. Vamos a crear un método para recuperar todos los usuarios en la base de datos:</p><pre><code class="language-js">userSchema.statics.getUsers = function() {
  return new Promise((resolve, reject) =&gt; {
    this.find((err, docs) =&gt; {
      if(err) {
        console.error(err)
        return reject(err)
      }
      
      resolve(docs)
    })
  })
}</code></pre><p>Usando <code>getUsers</code> en la clase Modelo devolverá todos los usuarios en la base de datos:</p><pre><code class="language-js">UserModel.getUsers()
  .then(docs =&gt; {
    console.log(docs)
  })
  .catch(err =&gt; {
    console.error(err)
  })</code></pre><p>Agregar instancias y métodos estáticos es un buen enfoque para implementar una interfaz para las interacciones de la base de datos en colecciones y registros.</p><h3 id="middleware">Middleware</h3><p>En este contexto Middleware son funciones que se ejecutan en etapas específicas de una canalización. Mongoose admite middleware para las siguientes operaciones:Aggregate</p><ul><li>Document</li><li>Model</li><li>Query</li></ul><p>Por ejemplo, los modelos tienen funciones <code>pre</code> y <code>post</code> que toman dos parámetros:</p><ol><li>Tipo de evento (‘init’, ‘validate’, ‘save’, ‘remove’)</li><li>Una devolución de llamada que se ejecuta con la referencia <strong><em>this</em></strong> a la instancia del modelo.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/0*iZwmyy25FSxuxXlH." class="kg-image" alt="0*iZwmyy25FSxuxXlH" width="800" height="310" loading="lazy"><figcaption>Ejemplo de Middleware (También conocidos como "ganchos" pre y post )</figcaption></figure><p>Probemos un ejemplo agregando dos campos llamados <code>createdAt</code> y <code>updatedAt</code> a nuestro esquema:</p><pre><code class="language-js">let mongoose = require('mongoose')

let userSchema = new mongoose.Schema({
  firstName: String,
  lastName: String,
  createdAt: Date,
  updatedAt: Date
})

module.exports = mongoose.model('User', userSchema)</code></pre><p>Cuando <code>model.save()</code> es llamado, existe un evento <code>pre(‘save’, …)</code> y un evento <code>post(‘save’, …)</code> que es activado. Para el segundo parámetro, puedes pasar una función que se llama cuando se activa el evento. Estas funciones llevan un parámetro a la siguiente función en la cadena de middleware.</p><p>Agreguemos un gancho pre-guardado y establezcamos valores para <code>createdAt</code> and <code>updatedAt</code>:</p><pre><code class="language-js">userSchema.pre('save', function (next) {
  let now = Date.now()
   
  this.updatedAt = now
  // Set a value for createdAt only if it is null
  if (!this.createdAt) {
    this.createdAt = now
  }
  
  // Call the next function in the pre-save chain
  next()    
})</code></pre><p>Creemos y guardemos nuestro modelo:</p><pre><code class="language-js">let UserModel = require('./user')

let model = new UserModel({
  fullName: 'Thomas Anderson'
}

msg.save()
   .then(doc =&gt; {
     console.log(doc)
   })
   .catch(err =&gt; {
     console.error(err)
   })</code></pre><p>Deberías ver los valores para <code>createdAt</code> y <code>updatedAt</code> cuando el registro que has creado se imprime:</p><pre><code class="language-json">{ _id: 5a7bbbeebc3b49cb919da675,
  firstName: 'Thomas',
  lastName: 'Anderson',
  updatedAt: 2018-02-08T02:54:38.888Z,
  createdAt: 2018-02-08T02:54:38.888Z,
  __v: 0 }</code></pre><h3 id="complementos-plugins-">Complementos (Plugins)</h3><p>Supongamos que queremos rastrear cuándo se creó un registro y cuándo se actualizó por última vez en cada colección de nuestra base de datos. En lugar de repetir el proceso anterior, podemos crear un complemento y aplicarlo a cada esquema.</p><p>Creemos un archivo <code>./src/model/plugins/timestamp.js</code> replicando la funcionalidad anterior como un módulo reusable:</p><pre><code class="language-js">module.exports = function timestamp(schema) {

  // Add the two fields to the schema
  schema.add({ 
    createdAt: Date,
    updatedAt: Date
  })

  // Create a pre-save hook
  schema.pre('save', function (next) {
    let now = Date.now()
   
    this.updatedAt = now
    // Set a value for createdAt only if it is null
    if (!this.createdAt) {
      this.createdAt = now
    }
   // Call the next function in the pre-save chain
   next()    
  })
}</code></pre><p>Para usar este complemento, simplemente lo pasamos a los esquemas que debería tener esta funcionalidad:</p><pre><code class="language-js">let timestampPlugin = require('./plugins/timestamp')

emailSchema.plugin(timestampPlugin)
userSchema.plugin(timestampPlugin)</code></pre><h2 id="construcci-n-de-consultas">Construcción de Consultas</h2><p>Mongoose tiene una API muy abundante que maneja muchas operaciones complejas compatibles con MongoDB. Considera una consulta en la que podamos crear componentes de consulta de forma incremental.<br>En este ejemplo, vamos a:</p><p>1.Buscar todos los usuarios<br>2.Omitir los primeros 100 registros<br>3.Limitar los resultados a 10 registros<br>4.Ordenar los resultados por el campo firstName<br>5.Seleccionar el nombre<br>6.Ejecutar esa consulta</p><pre><code class="language-js">UserModel.find()                   // find all users
         .skip(100)                // skip the first 100 items
         .limit(10)                // limit to 10 items
         .sort({firstName: 1}      // sort ascending by firstName
         .select({firstName: true} // select firstName only
         .exec()                   // execute the query
         .then(docs =&gt; {
            console.log(docs)
          })
         .catch(err =&gt; {
            console.error(err)
          })</code></pre><h3 id="cierre"><strong>Cierre</strong></h3><p>Apenas hemos arañado la superficie explorando algunas de las capacidades de Mongoose. Es una abundante biblioteca llena de funciones útiles y potentes que hacen que sea un placer trabajar con modelos de datos en la capa de aplicación.<br>Si bien puede interactuar con Mongo directamente usando Mongo Driver, Mongoose simplificará esa interacción al permitirle modelar relaciones entre datos y validarlos fácilmente.</p><p>Dato curioso: <a href="https://mongoosejs.com/">Mongoose</a> fue creado por <strong>Valeri Karpov</strong>, ¡Un ingeniero increíblemente talentoso! Él acuñó el término <a href="http://thecodebarbarian.com/2013/04/29//easy-web-prototyping-with-mongodb-and-nodejs"><strong>The MEAN Stack.</strong></a></p><p>Si este artículo te ha sido útil, <a href="https://twitter.com/intent/follow?screen_name=theoutlander">sígueme en Twitter</a>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/03/image-3.png" class="kg-image" alt="image-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/03/image-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2023/03/image-3.png 800w" sizes="(min-width: 720px) 720px" width="800" height="392" loading="lazy"></figure><p>También te puede gustar <a href="https://www.youtube.com/watch?v=egeHq-lYyxo">mi taller en youtube</a>: Cómo construir una API REST con Node | expreso | Mongo</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
