{"id":2067,"date":"2016-08-15T22:03:50","date_gmt":"2016-08-15T22:03:49","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2067"},"modified":"2025-06-13T23:32:49","modified_gmt":"2025-06-14T06:32:49","slug":"user-profile-store-advanced-data-modeling","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/user-profile-store-advanced-data-modeling\/","title":{"rendered":"Almac\u00e9n de perfiles de usuario: Modelado avanzado de datos - Parte 1"},"content":{"rendered":"<p style=\"text-align: left\">Pr\u00e1cticamente todas las organizaciones necesitan registrar y recuperar datos de usuarios. Con frecuencia, estos datos de usuario son permanentes, como las cuentas de usuario con configuraciones definidas, historiales y preferencias. Con la misma frecuencia, los datos son transitorios, como en el caso de las sesiones an\u00f3nimas con actividad reciente. En ambos casos, la organizaci\u00f3n necesitar\u00e1 un almac\u00e9n de perfiles de usuario\/almac\u00e9n de sesiones para persistir y consultar los datos. Como este tipo de datos es la base de muchas aplicaciones en la mayor\u00eda de las organizaciones, es imperativo que el dise\u00f1o de la base de datos de perfiles de usuario sea eficiente, disponible y escalable. Este post sobre c\u00f3mo almacenar las preferencias de los usuarios en una base de datos explora un sistema de este tipo.<\/p>\n<p style=\"text-align: left\">Vamos a ver un servicio de almacenamiento de perfiles (REST API) utilizando Couchbase como base de datos con un modelo de datos de usuario que juega con los puntos fuertes de Couchbase. Comenzaremos con todos los datos en un documento. Luego veremos c\u00f3mo y por qu\u00e9 podr\u00edamos normalizar este documento en documentos separados y la l\u00f3gica detr\u00e1s de los cambios. Todo esto en la perspectiva de lo que funcionar\u00e1 mejor para el modelo de datos de perfil de usuario y c\u00f3mo planeamos utilizar los poderes de Couchbase Server.<\/p>\n<h2 style=\"text-align: left\">Definici\u00f3n del servicio de perfil de usuario<\/h2>\n<p style=\"text-align: left\">Empecemos por definir el servicio de ejemplo y sus par\u00e1metros. Aqu\u00ed est\u00e1n los par\u00e1metros de dise\u00f1o que me di para este proyecto:<\/p>\n<ol>\n<li>Ser\u00e1 el almac\u00e9n de perfiles autorizado para todos los microservicios de una empresa ficticia orientados al cliente y expondr\u00e1 una API REST para soportar operaciones CRUD contra los datos.<\/li>\n<li>La API ser\u00e1 versionada con funcionalidad retenida y obsoleta de acuerdo con el documento de dise\u00f1o.<\/li>\n<li>El objetivo de tiempo de actividad es del 99,999% o superior.<\/li>\n<li>Ser capaz de configurar los perfiles de usuario para que se conserven durante X a\u00f1os despu\u00e9s de su \u00faltimo inicio de sesi\u00f3n y, preferiblemente, la base de datos deber\u00e1 gestionar la eliminaci\u00f3n de los datos de la cuenta junto con la configuraci\u00f3n de la aplicaci\u00f3n del tiempo de vida (TTL) en los objetos de cada usuario\".<\/li>\n<li>El servicio deber\u00eda ser capaz de realizar un m\u00ednimo de 50.000 autenticaciones y 10.000 b\u00fasquedas de perfiles de usuario principales por segundo en instancias de AWS de tama\u00f1o relativamente modesto.<\/li>\n<\/ol>\n<h2 style=\"text-align: left\">Definici\u00f3n de los servicios expuestos por la API REST<\/h2>\n<p style=\"text-align: left\">Es necesario empezar por mapear c\u00f3mo se utilizar\u00e1n los datos. Las interfaces que expondr\u00e1 mi servicio y cu\u00e1les se utilizar\u00e1n m\u00e1s y menos. Esto me ayudar\u00e1 a saber c\u00f3mo dise\u00f1ar mejor mis documentos. Couchbase me permite dise\u00f1ar un esquema de documentos basado en c\u00f3mo, cu\u00e1ndo y la frecuencia en la que la aplicaci\u00f3n usar\u00e1 los datos y no en c\u00f3mo la base de datos los almacenar\u00e1, como podr\u00edas estar forzado a hacer en un RDBMS.<\/p>\n<p style=\"text-align: left\">He aqu\u00ed algunos ejemplos de m\u00e9todos que uno puede tener para este servicio. No voy a enumerarlos todos y perder el tiempo, pero usted consigue la idea.<\/p>\n<ol>\n<li>getUserProfile(userID) - Obtiene todos los objetos del usuario en la base de datos. Se leer\u00e1 en una matriz de la clave establecida patr\u00f3n de nombre de objeto (por ejemplo, ) y luego hacer una operaci\u00f3n de obtenci\u00f3n masiva en todos los objetos del usuario.<\/li>\n<li>getSecurityQuestions(userID) - Comprueba en el documento login-info que el usuario est\u00e1 habilitado y si es as\u00ed, devuelve el documento de preguntas de seguridad del usuario. Si el usuario est\u00e1 deshabilitado, devolver\u00e1 un error.<\/li>\n<li>setSecurityQuestions(userID) - escribe el documento de preguntas de seguridad del usuario.<\/li>\n<li>authorizeUser(userID, passwordHash, IP) - obtiene el documento de autenticaci\u00f3n del usuario, llama a la funci\u00f3n isEnabled y si la cuenta est\u00e1 habilitada comprueba si la contrase\u00f1a coincide. Si coinciden, actualiza el documento con la IP y el \u00faltimo inicio de sesi\u00f3n.<\/li>\n<li>isEnabled(userID) - comprueba el documento login-info del usuario para ver si la cuenta est\u00e1 habilitada o no en el sistema. Devolver\u00e1 verdadero o falso.<\/li>\n<\/ol>\n<p style=\"text-align: left\">Encontrar\u00e1 una lista completa de los m\u00e9todos en la \u00faltima entrada del blog que trata sobre el desarrollo de la aplicaci\u00f3n y el c\u00f3digo de ejemplo.<\/p>\n<h2 style=\"text-align: left\">El documento inicial del usuario principal<\/h2>\n<p style=\"text-align: left\">He aqu\u00ed un ejemplo de documento de perfil de usuario con el que podr\u00eda empezar y que recoge todos los datos que necesitar\u00e1 mi servicio y que ser\u00eda una forma perfectamente v\u00e1lida de hacerlo.<\/p>\n<pre style=\"text-align: left\">key : hernandez94\r\n{\r\n        \"username\" : \"hernandez94\",\r\n        \"firstName\" : \"Jennifer\",\r\n        \"middleName\" : \"Maria\",\r\n        \"lastName\" : \"Hernandez\",\r\n        \"addresses\" : [\r\n                 { \"type\" : \"home\", \"addr1\" : \"1929 Crisanto Ave\", \"address\" : \"Apt 123\", \"addr3\" : \"c\/o  J. Hernandez\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94040\" },\r\n                 { \"type\" : \"work\", \"addr1\" : \"2700 W El Camino Real\", \"addr2\" : \"Suite #123\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94040\" },\r\n                 { \"type\" : \"billing\", \"addr1\" : \"P.O. Box 123456\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94041\" }\r\n        ],\r\n        \"emails\" : [\r\n                 { \"type\" : \"work\", \"addr\" : \"work@email.com\" },\r\n                 { \"type\" : \"personal\", \"addr\" : \"personal@email.com\", \"primary\" : true }\r\n        ],\r\n        \"phones\" : [\r\n                 { \"type\" : \"work\", \"num\" : \"+12345678900\" },\r\n                 { \"type\" : \"mobile\", \"num\" : \"+12345678901\" }\r\n        ],\r\n        \"createdate\" : \u201c2016-08-01 15:03:40\u201d,\r\n        \"lastlogin\": \"2016-08-01 17:03:40\",\r\n        \"pword\": \"app-hashed-password\",\r\n        \"loc\": \"IP or fqdn\",\r\n        \"enabled\" : true,\r\n        \"sec-questions\" : [\r\n                 { \"question1\" : \"Security question 1 goes here\", \"answer\" : \"Answer to security question 1 goes here\" },\r\n                 { \"question2\" : \"Security question 2 goes here\", \"answer\" : \"Answer to security question 2 goes here\" },\r\n                 { \"question3\" : \"Security question 3 goes here\", \"answer\" : \"Answer to security question 3 goes here\" }\r\n        ],\r\n        \"sec-roles\" : [101, 301, 345],\r\n        \"doc-type\" : \"user\"\r\n}\r\n<\/pre>\n<p style=\"text-align: left\">Este documento ocupa alrededor de 1,41kb y a\u00fan no se han rellenado todos los datos. As\u00ed que este documento podr\u00eda hacerse m\u00e1s grande dependiendo del usuario. Si tienes desarrolladores o eres un desarrollador al que le gusta a\u00f1adir y a\u00f1adir y a\u00f1adir datos a un documento o tabla, entonces podr\u00eda crecer mucho a lo largo de la evoluci\u00f3n de tu aplicaci\u00f3n\/servicio. Veamos c\u00f3mo optimizar este documento para c\u00f3mo y cu\u00e1ndo la aplicaci\u00f3n utilizar\u00e1 estos datos.<\/p>\n<h2 style=\"text-align: left\">Unas breves palabras sobre el acceso a datos en Couchbase<\/h2>\n<p style=\"text-align: left\">Para las partes principales de este servicio necesito la potencia y el rendimiento de acceder a mis datos a trav\u00e9s de una clave y consultar los datos lo menos posible. Sin rehacer <a href=\"https:\/\/www.couchbase.com\/blog\/es\/determine-data-access-in-couchbase\/\">mi otra entrada en el blog sobre el acceso a los datos<\/a> demasiado, Couchbase tiene m\u00faltiples formas de acceder a los datos. Si proporcionas el ObjectID del objeto(s) que quieres, tu aplicaci\u00f3n puede leer y escribir esos objetos excepcionalmente r\u00e1pido desde la cach\u00e9 gestionada del Servicio de Datos.<\/p>\n<p style=\"text-align: left\">Si quieres hacer una consulta usando el lenguaje N1QL de Couchbase (~98% compatible con ANSI 92 SQL) eso significa que tienes una pregunta de los datos y eso se puede hacer tambi\u00e9n a trav\u00e9s del Servicio de Consulta. Por su naturaleza de tener que hacer m\u00e1s trabajo, la consulta es menos performante que trabajar con datos por ObjectID. Es la diferencia entre tener una pregunta (consulta) y conocer ya la respuesta (ObjectID). (Para m\u00e1s informaci\u00f3n sobre por qu\u00e9 digo esto, consulte mi otra entrada del blog sobre \"<a href=\"https:\/\/www.couchbase.com\/blog\/es\/determine-data-access-in-couchbase\/\">C\u00f3mo las necesidades funcionales y de rendimiento determinan el acceso a los datos en Couchbase<\/a>&#8220;).<\/p>\n<p style=\"text-align: left\">Para este dise\u00f1o de esquema de base de datos de perfil de usuario, nos aseguraremos de que nuestros objetos puedan ser accedidos eficientemente por ambos medios cuando sea necesario. Los \"caminos calientes\" de la aplicaci\u00f3n ser\u00e1n accedidos por ObjectID tanto como podamos, pero tambi\u00e9n haremos consultas cuando sea necesario. Tenemos que cumplir los requisitos establecidos anteriormente en este documento.<\/p>\n<h2 style=\"text-align: left\">Optimizaci\u00f3n del documento principal de usuario<\/h2>\n<p style=\"text-align: left\">En el dise\u00f1o de un modelo de datos de usuario para este servicio, tenemos algunas opciones disponibles que son un tanto exclusivas de Couchbase y de c\u00f3mo escala, rinde y gestiona la memoria. Dado que todos los objetos son elegibles para ser guardados en la cach\u00e9 gestionada del Servicio de Datos, queremos que el modelo de datos de documentos y el patr\u00f3n de claves utilizado por nuestro servicio sea lo suficientemente flexible como para que los datos que necesitamos con frecuencia est\u00e9n en la cach\u00e9 gestionada y los datos utilizados con poca frecuencia puedan estar simplemente en el disco, lo cual est\u00e1 bien. Otras bases de datos de documentos NoSQL pueden hacer que pongas todo en un documento y luego consultes esos datos. La consulta con N1QL tambi\u00e9n est\u00e1 disponible en Couchbase, y la usaremos para prop\u00f3sitos espec\u00edficos. De nuevo, la arquitectura de Couchbase con su modelo de datos flexible y su cach\u00e9 gestionada integrada nos permite elegir d\u00f3nde y c\u00f3mo queremos utilizar este poder en nuestro beneficio.<\/p>\n<p style=\"text-align: left\">Utilizar\u00e9 un patr\u00f3n de claves y un modelo de datos normalizado, cuando tenga sentido. Haciendo esto, tenemos la capacidad de s\u00f3lo leer y escribir los datos exactos que necesitamos, cuando los necesitamos y como los necesitamos, pero cuando necesitamos consultar datos con N1QL, podemos hacer eso tambi\u00e9n. Algunos de estos patrones de dise\u00f1o pueden parecerte extra\u00f1os, pero as\u00ed es como podr\u00e1s ejecutar y escalar Couchbase f\u00e1cilmente para alcanzar decenas o cientos de miles de operaciones por segundo... o incluso m\u00e1s. En blogs posteriores, repasar\u00e9 c\u00f3mo queremos consultar algunos datos para hacer anal\u00edticas o algo m\u00e1s adelante.<\/p>\n<p style=\"text-align: left\">De nuevo, quiero intentar dise\u00f1ar los documentos en torno a la aplicaci\u00f3n obteniendo s\u00f3lo los datos que necesita, exactamente cuando los necesita y ley\u00e9ndolos con la clave y no consultando. Sin necesidad de \u00edndices, vistas, uniones, etc. As\u00ed es como obtendr\u00e1s el mejor rendimiento y escalabilidad con Couchbase.<\/p>\n<h2 style=\"text-align: left\">El documento Login-Info<\/h2>\n<p style=\"text-align: left\">He separado la informaci\u00f3n de inicio de sesi\u00f3n del usuario en un documento propio por varias razones, y utilizar\u00e9 esta misma filosof\u00eda para otros documentos m\u00e1s adelante.<\/p>\n<ol>\n<li>La informaci\u00f3n de inicio de sesi\u00f3n se necesita con bastante frecuencia, ya que los usuarios se autentican mucho en nuestra aplicaci\u00f3n, y cuando el servicio necesita estos datos, no necesita el resto de la informaci\u00f3n del usuario la mayor\u00eda de las veces. S\u00ed, Couchbase tiene edici\u00f3n de sub-documentos, pero como la mayor\u00eda de las bases de datos NoSQL, en el back-end el documento sigue siendo reensamblado y transmitido en su totalidad, por ejemplo, la replicaci\u00f3n entre clusters (XDCR). Prefiero evitar esto siempre que puedo.<\/li>\n<li>Preferir\u00eda que el servicio s\u00f3lo devolviera de la base de datos a la aplicaci\u00f3n un documento de 141 bytes que todos los 1,41k o m\u00e1s del documento principal. La edici\u00f3n de subdocumentos puede mitigar esto, pero no las dos razones siguientes.<\/li>\n<li>Por rendimiento, prefiero mantener una tonelada de documentos de 141 bytes en la cach\u00e9 gestionada en lugar de los m\u00e1s grandes cuando, de nuevo, no siempre necesito el documento completo. Mantener todo el documento en la cach\u00e9 puede no importar demasiado cuando tengo 100.000 usuarios y s\u00f3lo estoy haciendo 1000 operaciones por segundo, pero cuando tengo millones de usuarios y tengo que hacer 10s si no 100s de miles de operaciones por segundo y necesito mantener su rendimiento, se suma. Tanto en rendimiento como en recursos monetarios, concretamente RAM.<\/li>\n<li>Hacer esto tambi\u00e9n significa para los visitantes regulares de mi servicio, que su documento debe estar siempre en la cach\u00e9 gestionada para que obtengan el mejor rendimiento.<\/li>\n<\/ol>\n<p style=\"text-align: left\">Tambi\u00e9n quiero actualizar este documento con la fecha actual en el valor lastlogin y con la IP desde la que entraron cada vez que el usuario se conecta con \u00e9xito. Esto no es rastreado por Couchbase autom\u00e1ticamente, pero lo necesito para prop\u00f3sitos de an\u00e1lisis de negocio y para eliminar usuarios que no han iniciado sesi\u00f3n durante mucho tiempo. En este caso, s\u00f3lo estoy actualizando un documento muy peque\u00f1o.<\/p>\n<p style=\"text-align: left\">Dado que no es cr\u00edtico para las operaciones diarias de autenticaci\u00f3n de usuarios, para el requisito de eliminar usuarios que no han iniciado sesi\u00f3n en el sistema en X a\u00f1os, utilizaremos esto para otra entrada del blog.<\/p>\n<p style=\"text-align: left\">Tambi\u00e9n hay una entidad en el documento llamada \"enabled\" que se puede utilizar en el servicio para ver si el usuario tiene permiso para iniciar sesi\u00f3n o no.<\/p>\n<pre style=\"text-align: left\">key : login-info::hernandez94\r\n\r\n{\r\n        \"lastlogin\": \"2016-08-01 15:03:40\",\r\n        \"pword\": \"app-hashed-password\",\r\n        \"loc\": \"IP or fqdn\",\r\n        \"enabled\" : true,\r\n        \"doc-type\" : \"login-info\",\r\n        \"username\" : \"hernandez94\"\r\n}<\/pre>\n<p style=\"text-align: left\">Una parte cr\u00edtica aqu\u00ed es la clave del documento. Este tipo de patr\u00f3n clave es algo que es consistente en mi aplicaci\u00f3n como ver\u00e1s m\u00e1s adelante. Puedo f\u00e1cilmente hacer que la aplicaci\u00f3n concatene eso con el nombre de usuario \u00fanico. Esa clave es importante ya que no tendr\u00e9 que consultar este documento en Couchbase, tengo la clave. Conocer la clave significa que el SDK de Couchbase ya sabe la respuesta a la pregunta \"\u00bfD\u00f3nde est\u00e1 este dato que estoy buscando?\", mientras que consultar una base de datos es hacer esa pregunta a la base de datos y usar la potencia de la base de datos (y todo lo que eso conlleva) para encontrar la respuesta y devolver los datos. As\u00ed que conocer la clave y decirle a la base de datos que lea\/escriba ese objeto, especialmente si ya est\u00e1 en la cach\u00e9 gestionada, ser\u00e1 extremadamente r\u00e1pido con Couchbase. Incluso si el objeto est\u00e1 en el disco y no en la cach\u00e9 gestionada, ser\u00e1 r\u00e1pido y se colocar\u00e1 en la cach\u00e9 gestionada para que est\u00e9 listo para su uso en consultas posteriores. La gesti\u00f3n de la cach\u00e9 est\u00e1 detr\u00e1s de las escenas y no es algo que tu aplicaci\u00f3n tenga que saber.<\/p>\n<p style=\"text-align: left\">Tambi\u00e9n estaba pensando en separar la entidad \"enabled\" del documento JSON en su propio objeto de par clave\/valor ya que Couchbase soporta esto. Estaba pensando que podr\u00eda haber bastantes lugares en los que s\u00f3lo necesitar\u00eda saber si el usuario est\u00e1 habilitado en el sistema o no. Aunque es posible, decid\u00ed no hacerlo porque ya estaba empezando a normalizar mucho los datos y tengo que parar en alg\u00fan sitio. Este es uno donde por el bien de la complejidad, ten\u00eda sentido dejarlo estar.<\/p>\n<p style=\"text-align: left\">Una de las otras cosas a notar en este nuevo documento es que agregu\u00e9 las entidades doc-type y username al esquema del documento. Tambi\u00e9n las ver\u00e1s en todos los dem\u00e1s documentos. La raz\u00f3n para el tipo de documento es que puedo hacer una indexaci\u00f3n secundaria m\u00e1s tarde. El nombre de usuario es para la indexaci\u00f3n, sino tambi\u00e9n porque entonces puedo hacer JOINs en N1QL entre cualquiera de estos documentos y el nuevo documento principal ver\u00e1s que terminamos con. En partes posteriores de esta serie, usted ver\u00e1 m\u00e1s acerca de por qu\u00e9 es importante y c\u00f3mo lo usamos para nuestra ventaja.<\/p>\n<p style=\"text-align: left\">Para recapitular, separamos este fragmento de informaci\u00f3n del documento principal del usuario en un documento m\u00e1s peque\u00f1o por varias buenas razones. Necesitamos el documento a menudo, lo mantenemos peque\u00f1o para lecturas\/escrituras eficientes y, por lo tanto, deber\u00eda mantenerse en la cach\u00e9 gestionada para la mayor parte de los usuarios que nos importan. Adem\u00e1s, como podemos obtener el objeto por su clave, no tenemos que consultar la base de datos, por lo que las b\u00fasquedas son muy r\u00e1pidas. Tambi\u00e9n a\u00f1adimos valores al documento JSON para facilitar la consulta m\u00e1s adelante.<\/p>\n<h2 style=\"text-align: left\">Documento sobre cuestiones de seguridad<\/h2>\n<p style=\"text-align: left\">Cre\u00e9 el documento de preguntas de seguridad, ya que a diferencia del documento de informaci\u00f3n de inicio de sesi\u00f3n que se necesita muy a menudo, estos datos se necesitar\u00e1n muy raramente. Las veces que el servicio necesita esta informaci\u00f3n, espec\u00edficamente no necesita el resto de la informaci\u00f3n del usuario. Por lo tanto, ten\u00eda sentido dividirlo en su propio objeto y a\u00f1adir una clave que la aplicaci\u00f3n pudiera concatenar f\u00e1cilmente para obtener el documento por clave. Tambi\u00e9n convert\u00ed esto de una matriz a cada pregunta siendo su propio objeto. Por ejemplo, pregunta1.pregunta o pregunta2.respuesta y en el c\u00f3digo de mi aplicaci\u00f3n puedo generar aleatoriamente un n\u00famero entre 1 y 3 y luego utilizar una API de subdocumento para obtener s\u00f3lo esa pregunta. Tambi\u00e9n tendr\u00eda la opci\u00f3n de mostrar las tres preguntas dependiendo de c\u00f3mo funcione mi aplicaci\u00f3n. Me gusta tener opciones.<\/p>\n<pre style=\"text-align: left\">key : sec-questions::hernandez94\r\n\r\n{\r\n \"question1\" : { \"question\" : \"Security question 1 goes here\", \"answer\" : \"Answer to security question 1 goes here\" },\r\n    \"question2\" : { \"question\" : \"Security question 2 goes here\", \"answer\" : \"Answer to security question 2 goes here\" },\r\n    \"question3\" : { \"question\" : \"Security question 3 goes here\", \"answer\" : \"Answer to security question 3 goes here\" },\r\n \"doc-type\" : \"sec-questions\",\r\n \"username\" : \"hernandez94\"\r\n}<\/pre>\n<p style=\"text-align: left\">Adem\u00e1s, debido a que el documento no se utiliza muy a menudo es posible que este documento podr\u00eda caer fuera de la cach\u00e9 administrada y no me importa. Los usuarios lo usan con tan poca frecuencia, que si hay un peque\u00f1o impacto en el rendimiento por ir al disco a buscarlo, \u00a1que se aguante usuario! No estoy pagando para mantener todos estos datos en la RAM porque usted no puede recordar algo acerca de su cuenta de usuario.<\/p>\n<h2 style=\"text-align: left\">Documento de funciones de seguridad del usuario<\/h2>\n<p style=\"text-align: left\">Quer\u00eda tener una lista de roles de seguridad para asociar a un usuario. Como muchas otras cosas, cuando necesito esta informaci\u00f3n, no necesito otra informaci\u00f3n sobre el usuario. Probablemente tendr\u00e9 otro documento en alg\u00fan lugar definiendo los roles de seguridad a los que se asignan.<\/p>\n<pre style=\"text-align: left\">key : user-sec-roles::hernandez94\r\n\r\n{\r\n    \"sec-roles\" : [101, 301, 345],\r\n    \"doc-type\" : \"user-roles\",\r\n    \"username\" : \"hernandez94\"\r\n}\r\n<\/pre>\n<h2 style=\"text-align: left\">Documento de funciones de seguridad<\/h2>\n<p style=\"text-align: left\">Dispondr\u00e9 de otra serie de documentos en los que se definir\u00e1n las funciones de seguridad a las que corresponden.<\/p>\n<pre style=\"text-align: left\">key : sec-roles::101\r\n\r\n{\r\n    \"name\" : \"Administrator\",\r\n    \"descr\" : \"Administrators of the service\",\r\n    \"doc-type\" : \"sec-role\"\r\n}\r\n<\/pre>\n<p style=\"text-align: left\">Esto es interesante, ya que podr\u00eda meterme en problemas m\u00e1s adelante. Debido a que este documento podr\u00eda ser le\u00eddo con bastante frecuencia, podr\u00eda crear un punto caliente dependiendo de la frecuencia con la que mi aplicaci\u00f3n lo utilice. He visto un cliente que guardaba la configuraci\u00f3n de su aplicaci\u00f3n en Couchbase en un documento, pero lo le\u00eda como 10.000+ veces por segundo. Mientras que un solo nodo de Couchbase puede manejar eso f\u00e1cilmente, esto era adem\u00e1s de todo su otro tr\u00e1fico. As\u00ed que el \u00fanico nodo del cluster que ten\u00eda este documento estaba saturado. Esto no deber\u00eda ser un problema aqu\u00ed, pero es algo a tener en cuenta. Probablemente voy a seguir m\u00e1s adelante con un post sobre c\u00f3mo se podr\u00eda solucionar esto, pero 99 veces de cada 100, esto no deber\u00eda ser un problema. S\u00f3lo he visto un punto caliente en Couchbase esta vez y realmente fue un problema de dise\u00f1o de la aplicaci\u00f3n que lo caus\u00f3.<\/p>\n<h2 style=\"text-align: left\">Correo electr\u00f3nico, direcciones, tel\u00e9fonos Documentos<\/h2>\n<p style=\"text-align: left\">Podr\u00edas separar las matrices de email, tel\u00e9fonos y\/o direcciones del documento original dependiendo de c\u00f3mo tu aplicaci\u00f3n utilice los datos. Tal vez tenemos un m\u00e9todo getEmail() o getAddress() que se expone como parte de este servicio. El m\u00e9todo getMail() tomar\u00eda como entrada el nombre de usuario \u00fanico y ser\u00eda capaz de construir f\u00e1cilmente la clave (email-addr::hernandez94) para el documento. Como normalizar en cualquier base de datos, se puede ir demasiado lejos. As\u00ed que ten cuidado y hazlo s\u00f3lo si tienes una raz\u00f3n s\u00f3lida para hacerlo.<\/p>\n<pre style=\"text-align: left\">key : phones::mobile::hernandez94\r\n\r\n{\r\n \"doc-type\" : \"phone\",\r\n \"num\" : \"+12345678900\",\r\n \"type\" : \"mobile\",\r\n \"id\" : \"hernandez94\"\r\n}\r\n<\/pre>\n<p style=\"text-align: left\">Hacer documentos para cada n\u00famero de tel\u00e9fono que el usuario tiene como abajo me dar\u00eda opciones tanto para acceso KV como para acceso N1QL. La siguiente consulta me dar\u00eda todos los n\u00fameros de tel\u00e9fono de este usuario y su tipo (por ejemplo, m\u00f3vil, trabajo, etc.)<\/p>\n<pre style=\"text-align: left\">SELECT num, type FROM userprofiles WHERE id = \"hernandez94\" AND doc-type = \"phone\";\r\n<\/pre>\n<p style=\"text-align: left\">Tambi\u00e9n podr\u00eda concatenar la clave del documento anterior y obtenerla a trav\u00e9s de KV. Esto le da opciones.<\/p>\n<h2 style=\"text-align: left\">El nuevo documento principal<\/h2>\n<p style=\"text-align: left\">Este es el documento principal. Si los patrones de usuario de mi aplicaci\u00f3n lo dictaran, desglosar\u00eda cosas como direcciones y tel\u00e9fonos, pero a efectos de ejemplo he decidido dejarlo as\u00ed, ya que todos los datos que he dejado aqu\u00ed son datos que no necesito tan a menudo o que, cuando lo hago, los necesito al mismo tiempo. \u00bfPodr\u00eda normalizar m\u00e1s? S\u00ed, por ejemplo, podr\u00eda desglosar la fecha de creaci\u00f3n en un objeto de valor clave, ya que quiero registrarlo, pero muy rara vez lo necesito, pero por el momento esto me lleva a donde tengo que estar. No quiero volverme demasiado loco. Adem\u00e1s, cuantos m\u00e1s documentos tenga, m\u00e1s metadatos tendr\u00e1 tambi\u00e9n.<\/p>\n<pre style=\"text-align: left\">key : hernandez94\r\n\r\n{\r\n    \"firstName\" : \"Jennifer\",\r\n    \"middleName\" : \"Maria\",\r\n    \"lastName\" : \"Hernandez\",\r\n    \"addresses\" : [\r\n        { \"type\" : \"home\", \"addr1\" : \"1929 Crisanto Ave\", \"address\" : \"Apt 123\", \"addr3\" : \"c\/o J. Hernandez\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94040\" },\r\n        { \"type\" : \"work\", \"addr1\" : \"2700 W El Camino Real\", \"addr2\" : \"Suite #123\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94040\" },\r\n        { \"type\" : \"billing\", \"addr1\" : \"P.O. Box 123456\", \"city\" : \"Mountain View\", \"state\" : \"CA\", \"country\" : \"USA\", \"pcode\" : \"94041\" }\r\n    ],\r\n    \"phones\" : [\r\n        { \"type\" : \"work\", \"num\" : \"+12345678900\" },\r\n        { \"type\" : \"mobile\", \"num\" : \"+12345678901\" }\r\n    ],\r\n    \"createdate\" : \"2016-08-01 15:03:40\",\r\n    \"doc-type\" : \"user\"\r\n}\r\n<\/pre>\n<h2 style=\"text-align: left\">Ejemplo de c\u00f3digo Java<\/h2>\n<p style=\"text-align: left\">Este es un ejemplo de c\u00f3digo Java de una operaci\u00f3n de obtenci\u00f3n masiva para obtener todos los documentos asociados al usuario:<\/p>\n<p style=\"text-align: left\">Esto le permite obtener todos los documentos asociados a este usuario muy f\u00e1cil y r\u00e1pidamente. Algo as\u00ed como poner diferentes piezas de datos en diferentes tablas en una base de datos relacional y luego hacer una uni\u00f3n para obtener toda la informaci\u00f3n. Esto ser\u00eda MUCHO m\u00e1s r\u00e1pido que eso.<\/p>\n<pre style=\"text-align: left\">Cluster cluster = CouchbaseCluster.create();\r\nBucket bucket = cluster.openBucket();\r\n\r\nList foundDocs = Observable\r\n    .just( userID, \"sec-questions::\" + userID, \"login-info::\" + userID, \"user-sec-roles::\" + userID)\r\n    .flatMap(new Func1&lt;String, Observable&gt;() {\r\n       @Override\r\n       public Observable call(String id) {\r\n           return bucket.async().get(id);\r\n       }\r\n    })\r\n    .toList()\r\n    .toBlocking()\r\n    .single();\r\n<\/pre>\n<p style=\"text-align: left\">Podr\u00eda pensar en modificar el c\u00f3digo para asegurarme de que tengo todos los documentos cuando termine con esta llamada y si no hacer una lectura de r\u00e9plica para los documentos que faltan, en caso de que un nodo est\u00e9 ca\u00eddo, pero ya te haces una idea.<\/p>\n<p style=\"text-align: left\">Para m\u00e1s informaci\u00f3n sobre c\u00f3mo hacer \"bulk gets\", por favor consulta la documentaci\u00f3n de tu SDK de Couchbase.<\/p>\n<h2 style=\"text-align: left\">Resumen<\/h2>\n<p style=\"text-align: left\">Couchbase te ofrece una forma diferente de modelar tus datos en contraposici\u00f3n a otras bases de datos de documentos y especialmente a las bases de datos relacionales. Al dividir algunos datos en diferentes documentos, pero relacionados por la informaci\u00f3n en la clave y el documento, podemos obtener los datos exactos que necesitamos para la aplicaci\u00f3n cuando los necesitamos. Mantenemos frescos exactamente los datos que queremos en la cach\u00e9 gestionada que se utiliza a menudo, pero si necesitamos todos los documentos del usuario, podemos hacer una operaci\u00f3n masiva en todos ellos muy r\u00e1pidamente. La \u00faltima parte importante es el patr\u00f3n de claves utilizado aqu\u00ed. De nuevo, acceder a los objetos por clave es la diferencia entre conocer ya la respuesta y tener que hacer una pregunta como en otras bases de datos.<\/p>\n<p style=\"text-align: left\">Toda esta charla sobre rendimiento y patrones clave ignora las ocasiones en las que realmente queremos consultar los datos. Cuando tenemos preguntas como \"\u00bfCu\u00e1ntos usuarios tienen un c\u00f3digo postal de 98038?\". Pero, como he dicho antes, eso lo dejaremos para otra entrada de esta serie.<\/p>","protected":false},"excerpt":{"rendered":"<p>Virtually all organizations have a need to record and recall user data. Frequently, this user data is permanent, such as user accounts with defined settings, histories and preferences. Equally as frequent, the data is transient, as in the case of [&hellip;]<\/p>","protected":false},"author":23,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[1449,1447,1528,1450,1261,2215],"ppma_author":[9008],"class_list":["post-2067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-advanced-data-modeling","tag-data-modeling","tag-document-design","tag-document-normalization","tag-json","tag-user-profile"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>User Profile Database Design: How to Store User Preferences<\/title>\n<meta name=\"description\" content=\"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.\" \/>\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\/user-profile-store-advanced-data-modeling\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"User Profile Store: Advanced Data Modeling Part 1\" \/>\n<meta property=\"og:description\" content=\"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/user-profile-store-advanced-data-modeling\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-08-15T22:03:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:32:49+00:00\" \/>\n<meta name=\"author\" content=\"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/\"},\"author\":{\"name\":\"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2887e38425754897cea2d896bf082e6d\"},\"headline\":\"User Profile Store: Advanced Data Modeling Part 1\",\"datePublished\":\"2016-08-15T22:03:49+00:00\",\"dateModified\":\"2025-06-14T06:32:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/\"},\"wordCount\":3257,\"commentCount\":13,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"Advanced Data Modeling\",\"Data Modeling\",\"Document Design\",\"Document Normalization\",\"JSON\",\"user profile\"],\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/\",\"name\":\"User Profile Database Design: How to Store User Preferences\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2016-08-15T22:03:49+00:00\",\"dateModified\":\"2025-06-14T06:32:49+00:00\",\"description\":\"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#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\/user-profile-store-advanced-data-modeling\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"User Profile Store: Advanced Data Modeling Part 1\"}]},{\"@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\/2887e38425754897cea2d896bf082e6d\",\"name\":\"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/60a4ddb304fde12e65369919433b8dc7\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f704905856dcd1767d50024da51e2fa159eea665c85aff3224bc8763551d4e35?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f704905856dcd1767d50024da51e2fa159eea665c85aff3224bc8763551d4e35?s=96&d=mm&r=g\",\"caption\":\"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase\"},\"description\":\"Kirk Kirkconnell was a Senior Solutions Engineer at Couchbase working with customers in multiple capacities to assist them in architecting, deploying, and managing Couchbase. His expertise is in operations, hosting, and support of large-scale application and database infrastructures.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/kirk-kirkconnell\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"User Profile Database Design: How to Store User Preferences","description":"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.","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\/user-profile-store-advanced-data-modeling\/","og_locale":"es_MX","og_type":"article","og_title":"User Profile Store: Advanced Data Modeling Part 1","og_description":"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/user-profile-store-advanced-data-modeling\/","og_site_name":"The Couchbase Blog","article_published_time":"2016-08-15T22:03:49+00:00","article_modified_time":"2025-06-14T06:32:49+00:00","author":"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase","Est. reading time":"15 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/"},"author":{"name":"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2887e38425754897cea2d896bf082e6d"},"headline":"User Profile Store: Advanced Data Modeling Part 1","datePublished":"2016-08-15T22:03:49+00:00","dateModified":"2025-06-14T06:32:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/"},"wordCount":3257,"commentCount":13,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["Advanced Data Modeling","Data Modeling","Document Design","Document Normalization","JSON","user profile"],"articleSection":["Uncategorized"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/","url":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/","name":"User Profile Database Design: How to Store User Preferences","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2016-08-15T22:03:49+00:00","dateModified":"2025-06-14T06:32:49+00:00","description":"User profile database designs must be performant, available, and scalable. This Couchbase post shows how to store user preferences in such a database.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/user-profile-store-advanced-data-modeling\/#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\/user-profile-store-advanced-data-modeling\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"User Profile Store: Advanced Data Modeling Part 1"}]},{"@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\/2887e38425754897cea2d896bf082e6d","name":"Kirk Kirkconnell, Ingeniero Superior de Soluciones, Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/60a4ddb304fde12e65369919433b8dc7","url":"https:\/\/secure.gravatar.com\/avatar\/f704905856dcd1767d50024da51e2fa159eea665c85aff3224bc8763551d4e35?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f704905856dcd1767d50024da51e2fa159eea665c85aff3224bc8763551d4e35?s=96&d=mm&r=g","caption":"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase"},"description":"Kirk Kirkconnell fue Ingeniero Senior de Soluciones en Couchbase trabajando con clientes en m\u00faltiples capacidades para ayudarles en la arquitectura, despliegue y gesti\u00f3n de Couchbase. Su experiencia se centra en operaciones, alojamiento y soporte de aplicaciones a gran escala e infraestructuras de bases de datos.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/kirk-kirkconnell\/"}]}},"authors":[{"term_id":9008,"user_id":23,"is_guest":0,"slug":"kirk-kirkconnell","display_name":"Kirk Kirkconnell, Senior Solutions Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/f704905856dcd1767d50024da51e2fa159eea665c85aff3224bc8763551d4e35?s=96&d=mm&r=g","author_category":"","last_name":"Kirkconnell","first_name":"Kirk","job_title":"","user_url":"","description":"Kirk Kirkconnell fue Ingeniero Senior de Soluciones en Couchbase trabajando con clientes en m\u00faltiples capacidades para ayudarles en la arquitectura, despliegue y gesti\u00f3n de Couchbase. Su experiencia se centra en operaciones, alojamiento y soporte de aplicaciones a gran escala e infraestructuras de bases de datos."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2067","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\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=2067"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2067\/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=2067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=2067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=2067"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=2067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}