{"id":3868,"date":"2017-07-31T07:00:28","date_gmt":"2017-07-31T14:00:28","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=3868"},"modified":"2025-06-13T20:15:14","modified_gmt":"2025-06-14T03:15:14","slug":"creating-user-profile-store-with-node-js-nosql-database","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/creating-user-profile-store-with-node-js-nosql-database\/","title":{"rendered":"Crear un almac\u00e9n de perfiles de usuario con Node.js y una base de datos NoSQL"},"content":{"rendered":"<p>Hay muchos casos de uso para las bases de datos NoSQL, uno que encuentro con frecuencia es la creaci\u00f3n de un almac\u00e9n de perfiles de usuario y sesiones. Este caso de uso se presta a una <a href=\"https:\/\/www.couchbase.com\/blog\/es\/resources\/why-nosql\/\">Base de datos NoSQL<\/a>. A menudo, los perfiles deben ser flexibles y aceptar cambios en los datos. Aunque es posible en un RDBMS, requerir\u00eda m\u00e1s trabajo mantener los datos con penalizaciones de rendimiento.<\/p>\n<p>Kirk Kirkconnell escribi\u00f3 un ejemplo de alto nivel para crear un almac\u00e9n y una sesi\u00f3n de perfil de usuario con Couchbase: <a href=\"https:\/\/www.couchbase.com\/blog\/es\/user-profile-store-advanced-data-modeling\/\" target=\"_blank\" rel=\"noopener noreferrer\">Almac\u00e9n de perfiles de usuario: Modelado avanzado de datos<\/a>. Vamos a ampliar estos conceptos e implementar un almac\u00e9n de perfiles de usuario utilizando bases de datos Node.js y <a href=\"https:\/\/www.couchbase.com\/blog\/es\/\" target=\"_blank\" rel=\"noopener noreferrer\">Servidor Couchbase<\/a>.<\/p>\n<p><strong>Este tutorial ha sido actualizado el 4 de enero de 2021 por <a href=\"https:\/\/www.couchbase.com\/blog\/es\/author\/eric-bishard\/\">Eric Bishard<\/a> para trabajar con Couchbase <a href=\"https:\/\/docs.couchbase.com\/nodejs-sdk\/3.1\/hello-world\/start-using-sdk.html\">SDK de NodeJS 3<\/a>!<\/strong><\/p>\n<p><!--more--><\/p>\n<p>Antes de escribir algo de c\u00f3digo, vamos a averiguar lo que estamos tratando de lograr.<\/p>\n<p>Cuando se trata de gestionar los datos de un usuario, necesitamos una forma de crear un almac\u00e9n de perfiles de usuario y una sesi\u00f3n, y asociarles otros documentos. Definamos algunas reglas en torno a este concepto de almac\u00e9n de perfiles de usuario:<\/p>\n<ul>\n<li>Almacene los datos de la cuenta, como el nombre de usuario y la contrase\u00f1a, en un documento de perfil.<\/li>\n<li>Pasar datos sensibles del usuario con cada solicitud de acci\u00f3n del usuario.<\/li>\n<li>Utiliza una sesi\u00f3n que expira despu\u00e9s de un tiempo determinado.<\/li>\n<li>Documentos de sesi\u00f3n almacenados con un l\u00edmite de caducidad.<\/li>\n<\/ul>\n<p>Podemos gestionar todo esto con los siguientes puntos finales de la API:<\/p>\n<ul>\n<li>POST \/account - Crear un nuevo perfil de usuario con informaci\u00f3n de la cuenta<\/li>\n<li>POST \/login - Validar la informaci\u00f3n de la cuenta<\/li>\n<li>GET \/account - Obtener informaci\u00f3n de la cuenta<\/li>\n<li>POST \/blog - Crear una nueva entrada de blog asociada a un usuario<\/li>\n<li>GET \/blogs - Obtener todas las entradas de blog de un usuario concreto<\/li>\n<\/ul>\n<p>Estos endpoints formar\u00e1n parte de nuestro API backend utilizando el SDK Node.js de Couchbase Server (este art\u00edculo ha sido actualizado para utilizar la versi\u00f3n 3.1.x).<\/p>\n<h2>Creaci\u00f3n de la API con Node y Express<\/h2>\n<p>Vamos a crear un directorio de proyecto para nuestra aplicaci\u00f3n Node.js e instalar nuestras dependencias.<\/p>\n<pre class=\"lang:default decode:true\">mkdir blog-api \u00a0&amp;&amp;\u00a0 cd blog-api \u00a0&amp;&amp;\u00a0 npm init -y\r\nnpm install couchbase express body-parser uuid bcryptjs cors --save<\/pre>\n<p>Esto crea un directorio de trabajo para nuestro proyecto e inicializa un nuevo proyecto Node. Nuestras dependencias incluyen <a href=\"https:\/\/docs.couchbase.com\/nodejs-sdk\/3.1\/hello-world\/start-using-sdk.html\">SDK de Node.js para Couchbase<\/a> y Express Framework y otras bibliotecas de utilidades como <code>body-parser<\/code> para aceptar datos JSON a trav\u00e9s de peticiones POST, <code>uuid<\/code> para generar claves \u00fanicas y <code>bcryptjs<\/code> hash de nuestras contrase\u00f1as para disuadir a los usuarios malintencionados.<\/p>\n<p>Vamos a arrancar nuestra aplicaci\u00f3n con un archivo <strong>servidor.js<\/strong> file:<\/p>\n<pre class=\"lang:default decode:true\">const couchbase = require('couchbase')\r\nconst express = require('express')\r\nconst uuid = require('uuid')\r\nconst bodyParser = require('body-parser')\r\nconst bcrypt = require('bcryptjs')\r\nconst cors = require('cors')\r\n\r\nconst app = express()\r\n\r\napp.use(cors())\r\napp.use(bodyParser.json())\r\napp.use(bodyParser.urlencoded({ extended: true }))\r\n\r\nconst cluster = new couchbase.Cluster('couchbase:\/\/localhost', {\r\n  username: 'Administrator', password: 'password'\r\n})\r\nconst bucket = cluster.bucket('blog')\r\nconst collection = bucket.defaultCollection()\r\n\r\nconst server = app.listen(3000, () =&gt; console.info(`Running on port ${server.address().port}...`))<\/pre>\n<p>El c\u00f3digo anterior requiere nuestras dependencias e inicializa una aplicaci\u00f3n Express que se ejecuta en el puerto 3000 contra Couchbase Server utilizando un bucket llamado <code>blog<\/code>.<\/p>\n<p>Tambi\u00e9n necesitamos crear un \u00edndice en Couchbase Server porque usaremos el lenguaje de consulta N1QL para uno de nuestros endpoints. Si accedemos a nuestra consola web de Couchbase Server ejecut\u00e1ndose localmente en <strong>localhost:8091<\/strong>podemos hacer clic en el bot\u00f3n <strong>Consulta<\/strong> y ejecute esta sentencia en el Editor de Consultas:<\/p>\n<pre class=\"lang:default decode:true\">CREATE INDEX `blogbyuser` ON `default`(type, pid);<\/pre>\n<p>Dado que obtendremos todas las entradas de blog para un id de perfil concreto, obtendremos un mejor rendimiento utilizando este \u00edndice espec\u00edfico en lugar de un \u00edndice primario general. Los \u00edndices primarios no se recomiendan para c\u00f3digo de nivel de producci\u00f3n.<\/p>\n<h2>Guardar un nuevo usuario en el almac\u00e9n de perfiles<\/h2>\n<p>Sabemos que un perfil de usuario puede contener cualquier informaci\u00f3n que describa a un usuario. Informaci\u00f3n como direcci\u00f3n, tel\u00e9fono, redes sociales, etc. Nunca es buena idea almacenar las credenciales de la cuenta en el mismo documento que la informaci\u00f3n b\u00e1sica de nuestro perfil. Necesitaremos un m\u00ednimo de dos documentos para cada usuario, echemos un vistazo a c\u00f3mo se estructurar\u00e1n esos documentos.<\/p>\n<p>Nuestro documento de perfil tendr\u00e1 una clave a la que haremos referencia en nuestros documentos relacionados. Esta clave es un UUID autogenerado: <code>b181551f-071a-4539-96a5-8a3fe8717faf<\/code>.<\/p>\n<p>Nuestro documento de perfil tendr\u00e1 un valor JSON que incluye dos propiedades: <code>correo electr\u00f3nico<\/code>\u00a0y un <code>tipo<\/code> propiedad. En <code>tipo<\/code> es un indicador importante que describe nuestro documento de forma similar a como una tabla organiza los registros en una base de datos relacional. Se trata de una convenci\u00f3n est\u00e1ndar en una base de datos de documentos.<\/p>\n<pre class=\"lang:default decode:true\">{\r\n  \"type\": \"profile\",\r\n  \"email\": \"user1234@gmail.com\"\r\n}<\/pre>\n<p>El documento de cuenta asociado a nuestro perfil tendr\u00e1 una clave igual al email de nuestro usuario:<br \/>\n<code>user1234@gmail.com<\/code> y este documento tendr\u00e1 un <code>tipo<\/code>as\u00ed como un <code>pid<\/code> refiri\u00e9ndose a la clave de nuestro documento de perfil junto con <code>correo electr\u00f3nico<\/code> y hash <code>contrase\u00f1a<\/code>.<\/p>\n<pre class=\"lang:default decode:true\">{\r\n  \"type\": \"account\",\r\n  \"pid\": \"b181551f-071a-4539-96a5-8a3fe8717faf\",\r\n  \"email\": \"user1234@gmail.com\",\r\n  \"password\": \"$2a$10$tZ23pbQ1sCX4BknkDIN6NekNo1p\/Xo.Vfsttm.USwWYbLAAspeWsC\"\r\n}<\/pre>\n<p>Genial, hemos establecido un modelo para cada documento y una estrategia para relacionar esos documentos sin restricciones de base de datos.<\/p>\n<h2>Un punto final para la creaci\u00f3n de cuentas<\/h2>\n<p>A\u00f1ada el siguiente c\u00f3digo a nuestro <code>servidor.js<\/code> file:<\/p>\n<pre class=\"lang:default decode:true\">app.post(\"\/account\", async (request, response) =&gt; {\r\n  if (!request.body.email) {\r\n    return response.status(401).send({ \"message\": \"An `email` is required\" })\r\n  } else if (!request.body.password) {\r\n    return response.status(401).send({ \"message\": \"A `password` is required\" })\r\n  }\r\n\r\n  const id = uuid.v4()\r\n  const account = {\r\n    \"type\": \"account\",\r\n    \"pid\": id,\r\n    \"email\": request.body.email,\r\n    \"password\": bcrypt.hashSync(request.body.password, 10)\r\n  }\r\n  const profile = {\r\n    \"type\": \"profile\",\r\n    \"email\": request.body.email\r\n  }\r\n\r\n  await collection.insert(id, profile)\r\n    .then(async () =&gt; {\r\n      await collection.insert(request.body.email, account)\r\n        .then((result) =&gt; {\r\n          result.pid = id\r\n          return response.send(result)\r\n        })\r\n        .catch(async (e) =&gt; {\r\n          await collection.remove(id)\r\n            .then(() =&gt; {\r\n              console.error(`account creation failed, removed: ${id}`)\r\n              return response.status(500).send(e)\r\n            })\r\n            .catch(e =&gt; response.status(500).send(e))\r\n        })\r\n    })\r\n    .catch(e =&gt; response.status(500).send(e))\r\n})<\/pre>\n<p>Desglosemos este c\u00f3digo.<\/p>\n<p>En primer lugar, comprobamos que tanto an <code>correo electr\u00f3nico<\/code> y <code>contrase\u00f1a<\/code> existen en la solicitud.<\/p>\n<p>A continuaci\u00f3n, creamos un <code>cuenta<\/code> y <code>perfil<\/code> en funci\u00f3n de los datos enviados en la solicitud. La direcci\u00f3n <code>pid<\/code> que estamos guardando en el\u00a0<code>cuenta<\/code> es una clave \u00fanica. Se establecer\u00e1 como la clave del documento para nuestro <code>perfil<\/code> objeto.<\/p>\n<p>En <strong>cuenta<\/strong> utiliza el correo electr\u00f3nico como clave. En el futuro, si se necesitan otros datos de la cuenta (como correo electr\u00f3nico alternativo, login social, etc.) podremos asociar otros documentos al perfil.<\/p>\n<p>En lugar de guardar la contrase\u00f1a en el archivo <code>cuenta<\/code> como texto sin formato, le aplicamos un hash con <a href=\"https:\/\/www.npmjs.com\/package\/bcrypt\">Bcrypt<\/a>. La contrase\u00f1a se elimina del <code>perfil<\/code> para mayor seguridad. Para m\u00e1s informaci\u00f3n sobre el hash de contrase\u00f1as, consulte <a href=\"https:\/\/www.couchbase.com\/blog\/es\/hashing-passwords-stored-in-couchbase-server-with-nodejs\/\" target=\"_blank\" rel=\"noopener noreferrer\">este tutorial<\/a>.<\/p>\n<p>Con los datos listos, podemos insertarlos en Couchbase. El objetivo de este guardado es ser todo o nada. Queremos que tanto el <strong>cuenta<\/strong> y <strong>perfil<\/strong> se creen con \u00e9xito, de lo contrario, se deshar\u00e1 todo. Dependiendo del \u00e9xito, devolveremos alguna informaci\u00f3n al cliente.<\/p>\n<p>Podr\u00edamos haber utilizado consultas N1QL para insertar los datos, pero es m\u00e1s f\u00e1cil utilizar operaciones CRUD sin penalizaci\u00f3n en el rendimiento.<\/p>\n<h2>Uso de testigos de sesi\u00f3n para datos sensibles<\/h2>\n<p>Con el perfil de usuario y la cuenta creados, queremos que el usuario inicie sesi\u00f3n y comience a realizar actividades que almacenar\u00e1n datos y los asociar\u00e1n a \u00e9l.<\/p>\n<p>Queremos conectarnos y establecer una sesi\u00f3n que se almacenar\u00e1 en la base de datos haciendo referencia a nuestro perfil de usuario. Con el tiempo, este documento caducar\u00e1 y se eliminar\u00e1 de la base de datos.<\/p>\n<p>El modelo de sesi\u00f3n tendr\u00e1 el siguiente aspecto:<\/p>\n<pre class=\"lang:default decode:true\">{\r\n  \"type\": \"session\",\r\n  \"id\": \"ce0875cb-bd27-48eb-b561-beee33c9f405\",\r\n  \"pid\": \"b181551f-071a-4539-96a5-8a3fe8717faf\"\r\n}<\/pre>\n<p>Este documento, como los dem\u00e1s, tiene una <code>tipo<\/code>. Al igual que con el <strong>cuenta<\/strong> tiene un <code>pid<\/code> que hace referencia a un perfil de usuario.<\/p>\n<p>El c\u00f3digo que lo hace posible se encuentra en la secci\u00f3n <strong>inicio de sesi\u00f3n<\/strong> punto final:<\/p>\n<pre class=\"lang:default decode:true\">app.post(\"\/login\", async (request, response) =&gt; {\r\n  if (!request.body.email) {\r\n    return response.status(401).send({ \"message\": \"An `email` is required\" })\r\n  } else if (!request.body.password) {\r\n    return response.status(401).send({ \"message\": \"A `password` is required\" })\r\n  }\r\n\r\n  await collection.get(request.body.email)\r\n    .then(async (result) =&gt; {\r\n      if (!bcrypt.compareSync(request.body.password, result.value.password)) {\r\n        return response.status(500).send({ \"message\": \"Password invalid\" })\r\n      }\r\n      var session = {\r\n        \"type\": \"session\",\r\n        \"id\": uuid.v4(),\r\n        \"pid\": result.value.pid\r\n      }\r\n      await collection.insert(session.id, session, { \"expiry\": 3600 })\r\n        .then(() =&gt; response.send({ \"sid\": session.id }))\r\n        .catch(e =&gt; response.status(500).send(e))\r\n    })\r\n    .catch(e =&gt; response.status(500).send(e))\r\n})<\/pre>\n<p>Despu\u00e9s de validar los datos entrantes, hacemos una b\u00fasqueda de cuentas por direcci\u00f3n de correo electr\u00f3nico. Si se obtienen datos para el correo electr\u00f3nico, podemos comparar la contrase\u00f1a entrante con la contrase\u00f1a cifrada obtenida en la b\u00fasqueda de cuentas. Si esto tiene \u00e9xito, podemos crear una nueva sesi\u00f3n para el usuario.<\/p>\n<p>A diferencia de la operaci\u00f3n de inserci\u00f3n anterior, establecemos una caducidad del documento de una hora (3600 s). Si no se actualiza la caducidad, el documento desaparecer\u00e1. Esto es bueno porque obliga al usuario a registrarse de nuevo y obtener una nueva sesi\u00f3n. Este token de sesi\u00f3n ser\u00e1 pasado con cada solicitud futura en lugar de la contrase\u00f1a.<\/p>\n<h2>Gesti\u00f3n de una sesi\u00f3n de usuario con tokens<\/h2>\n<p>Queremos obtener informaci\u00f3n sobre nuestro perfil de usuario, as\u00ed como asociar nuevas cosas al perfil. Para ello, confirmamos la autoridad a trav\u00e9s de la sesi\u00f3n.<\/p>\n<p>Podemos confirmar que la sesi\u00f3n es v\u00e1lida utilizando middleware. Una funci\u00f3n Middleware puede ser a\u00f1adida a cualquier endpoint Express. Esta validaci\u00f3n es una funci\u00f3n simple que tendr\u00e1 acceso a la petici\u00f3n HTTP de nuestro endpoint:<\/p>\n<pre class=\"lang:default decode:true\">const validate = async(request, response, next) =&gt; {\r\n  const authHeader = request.headers[\"authorization\"]\r\n  if (authHeader) {\r\n    bearerToken = authHeader.split(\" \")\r\n    if (bearerToken.length == 2) {\r\n      await collection.get(bearerToken[1])\r\n        .then(async(result) =&gt; {\r\n          request.pid = result.value.pid\r\n          await collection.touch(bearerToken[1], 3600)\r\n            .then(() =&gt; next())\r\n            .catch((e) =&gt; console.error(e.message))\r\n        })\r\n        .catch((e) =&gt; response.status(401).send({ \"message\": \"Invalid session token\" }))\r\n    }\r\n  } else {\r\n    response.status(401).send({ \"message\": \"An authorization header is required\" })\r\n  }\r\n}<\/pre>\n<p>Aqu\u00ed estamos comprobando la solicitud de una cabecera de autorizaci\u00f3n. Si tenemos un token de portador v\u00e1lido con id de sesi\u00f3n (sid), podemos hacer una b\u00fasqueda. El documento de sesi\u00f3n contiene el identificador de perfil. Si la b\u00fasqueda de sesi\u00f3n tiene \u00e9xito, guardamos el id de perfil (pid) en la petici\u00f3n.<\/p>\n<p>A continuaci\u00f3n, refrescamos la expiraci\u00f3n de la sesi\u00f3n y nos movemos a trav\u00e9s del middleware y de vuelta al endpoint. Si la sesi\u00f3n no existe, no se pasar\u00e1 ning\u00fan id de perfil y la solicitud fallar\u00e1.<\/p>\n<p>Ahora podemos utilizar nuestro middleware para obtener informaci\u00f3n sobre nuestro perfil en nuestro endpoint de cuenta:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/account\", validate, async (request, response) =&gt; {\r\n  try {\r\n    await collection.get(request.pid)\r\n      .then((result) =&gt; response.send(result.value))\r\n      .catch((e) =&gt; response.status(500).send(e))\r\n  } catch (e) {\r\n    console.error(e.message)\r\n  }\r\n})<\/pre>\n<p>F\u00edjese en el <code>valide<\/code> y luego el resto de la solicitud. El sitio <code>solicitud.pid<\/code> fue establecido por el middleware y nos conseguir\u00e1 un documento de perfil particular para ese id.<\/p>\n<p>A continuaci\u00f3n, creamos un endpoint para a\u00f1adir un art\u00edculo de blog para el usuario:<\/p>\n<pre class=\"lang:default decode:true\">app.post(\"\/blog\", validate, async(request, response) =&gt; {\r\n  if(!request.body.title) {\r\n    return response.status(401).send({ \"message\": \"A `title` is required\" })\r\n  } else if(!request.body.content) {\r\n    return response.status(401).send({ \"message\": \"A `content` is required\" })\r\n  }\r\n  var blog = {\r\n    \"type\": \"blog\",\r\n    \"pid\": request.pid,\r\n    \"title\": request.body.title,\r\n    \"content\": request.body.content,\r\n    \"timestamp\": (new Date()).getTime()\r\n  }\r\n  const uniqueId = uuid.v4()\r\n  collection.insert(uniqueId, blog)\r\n    .then(() =&gt; response.send(blog))\r\n    .catch((e) =&gt; response.status(500).send(e))\r\n})<\/pre>\n<p>Asumiendo que el middleware ha tenido \u00e9xito, creamos un objeto blog con un <code>tipo<\/code> y <code>pid<\/code>. A continuaci\u00f3n, podemos guardarlo en la base de datos.<\/p>\n<p>La consulta de todas las entradas de blog de un usuario concreto no es muy diferente:<\/p>\n<pre class=\"lang:default decode:true\">app.get(\"\/blogs\", validate, async(request, response) =&gt; {\r\n  try {\r\n    const query = `SELECT * FROM \\`blog\\` WHERE type = 'blog' AND pid = $PID;`\r\n    const options = { parameters: { PID: request.pid } }\r\n    await cluster.query(query, options)\r\n      .then((result) =&gt; response.send(result.rows))\r\n      .catch((e) =&gt; response.status(500).send(e))\r\n  } catch (e) {\r\n    console.error(e.message)\r\n  }\r\n})<\/pre>\n<p>Como necesitamos consultar por la propiedad del documento en lugar de por la clave del documento, utilizaremos una consulta N1QL y un \u00edndice que creamos previamente.<\/p>\n<p>El documento <code>tipo<\/code> y <code>pid<\/code> se pasan a la consulta que devuelve todos los documentos de ese perfil concreto.<\/p>\n<h2>Conclusi\u00f3n<\/h2>\n<p>Acabas de ver c\u00f3mo crear un almac\u00e9n y una sesi\u00f3n de perfil de usuario usando Node.js y NoSQL. Este es un gran seguimiento de la explicaci\u00f3n de alto nivel de Kirk en su <a href=\"https:\/\/www.couchbase.com\/blog\/es\/user-profile-store-advanced-data-modeling\/\" target=\"_blank\" rel=\"noopener noreferrer\">art\u00edculo<\/a>.<\/p>\n<p>Como ya se ha mencionado, el <strong>cuenta<\/strong> podr\u00edan representar una forma de credenciales de inicio de sesi\u00f3n en la que podr\u00edas tener un documento para la autenticaci\u00f3n b\u00e1sica (autenticaci\u00f3n de Facebook, etc.) haciendo referencia al mismo documento de perfil. En lugar de utilizar un UUID para la sesi\u00f3n, se podr\u00eda utilizar un JSON Web Token (JWT) o quiz\u00e1s algo m\u00e1s seguro.<\/p>\n<p>En <a href=\"https:\/\/www.couchbase.com\/blog\/es\/creating-front-end-user-profile-store-angular-typescript\/\">El siguiente tutorial de esta serie nos ayudar\u00e1 a crear un front-end cliente<\/a> para esta API.<\/p>\n<p>El c\u00f3digo terminado, las colecciones de Postman y las variables de entorno disponibles en el archivo <a href=\"https:\/\/github.com\/couchbaselabs\/couchbase-nodejs-blog-api\">couchbaselabs \/ couchbase-nodejs-blog-api<\/a> en GitHub.<\/p>\n<p>Para obtener m\u00e1s informaci\u00f3n sobre el uso de Couchbase con Node.js, consulte la p\u00e1gina <a href=\"https:\/\/www.couchbase.com\/blog\/es\/developers\/\" target=\"_blank\" rel=\"noopener noreferrer\">Portal para desarrolladores de Couchbase<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>There are many use-cases for NoSQL databases, one that I encounter frequently is creating a user profile store and session. This use-case lends itself to a NoSQL database. Profiles often need to be flexible and accept data changes. While possible [&hellip;]<\/p>","protected":false},"author":63,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1815,1816,9327,1822],"tags":[1572,1543,1725,2019,2020],"ppma_author":[9032],"class_list":["post-3868","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-best-practices-and-tutorials","category-couchbase-server","category-javascript","category-node-js","tag-database","tag-javascript","tag-nosql-database","tag-profile-store","tag-users"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>User Profile Store: Create with Node.js and NoSQL Database<\/title>\n<meta name=\"description\" content=\"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/creating-user-profile-store-with-node-js-nosql-database\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create a User Profile Store with Node.js and a NoSQL Database\" \/>\n<meta property=\"og:description\" content=\"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/creating-user-profile-store-with-node-js-nosql-database\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2017-07-31T14:00:28+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:15:14+00:00\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Create a User Profile Store with Node.js and a NoSQL Database\",\"datePublished\":\"2017-07-31T14:00:28+00:00\",\"dateModified\":\"2025-06-14T03:15:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/\"},\"wordCount\":1520,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"database\",\"javascript\",\"NoSQL Database\",\"profile store\",\"users\"],\"articleSection\":[\"Application Design\",\"Best Practices and Tutorials\",\"Couchbase Server\",\"JavaScript\",\"Node.js\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/\",\"name\":\"User Profile Store: Create with Node.js and NoSQL Database\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2017-07-31T14:00:28+00:00\",\"dateModified\":\"2025-06-14T03:15:14+00:00\",\"description\":\"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Create a User Profile Store with Node.js and a NoSQL Database\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\/\/www.thepolyglotdeveloper.com\",\"https:\/\/www.facebook.com\/thepolyglotdeveloper\",\"https:\/\/x.com\/nraboy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"User Profile Store: Create with Node.js and NoSQL Database","description":"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/creating-user-profile-store-with-node-js-nosql-database\/","og_locale":"es_MX","og_type":"article","og_title":"Create a User Profile Store with Node.js and a NoSQL Database","og_description":"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/creating-user-profile-store-with-node-js-nosql-database\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2017-07-31T14:00:28+00:00","article_modified_time":"2025-06-14T03:15:14+00:00","author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"7 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Create a User Profile Store with Node.js and a NoSQL Database","datePublished":"2017-07-31T14:00:28+00:00","dateModified":"2025-06-14T03:15:14+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/"},"wordCount":1520,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["database","javascript","NoSQL Database","profile store","users"],"articleSection":["Application Design","Best Practices and Tutorials","Couchbase Server","JavaScript","Node.js"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/","url":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/","name":"User Profile Store: Create with Node.js and NoSQL Database","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2017-07-31T14:00:28+00:00","dateModified":"2025-06-14T03:15:14+00:00","description":"Profiles often need to be flexible and accept data changes. Find out how to implement a user profile store using Node.js databases and Couchbase Server.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/creating-user-profile-store-with-node-js-nosql-database\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Create a User Profile Store with Node.js and a NoSQL Database"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, Defensor del Desarrollador, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"Nic Raboy es un defensor de las tecnolog\u00edas modernas de desarrollo web y m\u00f3vil. Tiene experiencia en Java, JavaScript, Golang y una variedad de frameworks como Angular, NativeScript y Apache Cordova. Nic escribe sobre sus experiencias de desarrollo relacionadas con hacer el desarrollo web y m\u00f3vil m\u00e1s f\u00e1cil de entender.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/nic-raboy-2\/"}]}},"authors":[{"term_id":9032,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","author_category":"","last_name":"Raboy","first_name":"Nic","job_title":"","user_url":"https:\/\/www.thepolyglotdeveloper.com","description":"Nic Raboy es un defensor de las tecnolog\u00edas modernas de desarrollo web y m\u00f3vil. Tiene experiencia en Java, JavaScript, Golang y una variedad de frameworks como Angular, NativeScript y Apache Cordova. Nic escribe sobre sus experiencias de desarrollo relacionadas con hacer el desarrollo web y m\u00f3vil m\u00e1s f\u00e1cil de entender."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/3868","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=3868"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/3868\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=3868"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=3868"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=3868"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=3868"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}