{"id":2521,"date":"2017-02-03T16:05:12","date_gmt":"2017-02-03T16:05:12","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2521"},"modified":"2025-06-13T20:57:15","modified_gmt":"2025-06-14T03:57:15","slug":"moving-from-sql-server-to-couchbase-part-1-data-modeling","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","title":{"rendered":"Pasar de SQL Server a Couchbase Parte 1: Modelado de datos"},"content":{"rendered":"<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>En esta serie de entradas de blog, voy a exponer las consideraciones a tener en cuenta al pasar a una base de datos de documentos cuando se tiene una experiencia relacional. En concreto, Microsoft SQL Server en comparaci\u00f3n con <a href=\"https:\/\/www.couchbase.com\/blog\/es\/developers\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Servidor Couchbase<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En tres partes, voy a cubrir:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Modelado de datos (esta entrada del blog)<\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-server-couchbase-data-migration\/\">Los propios datos<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/es\/moving-sql-server-couchbase-app-migration\/\">Aplicaciones que utilizan los datos<\/a><\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>El objetivo es establecer algunas directrices generales que pueda aplicar a la planificaci\u00f3n y el dise\u00f1o de su aplicaci\u00f3n.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Si quieres seguirme, he creado una aplicaci\u00f3n que demuestra Couchbase y SQL Server lado a lado. <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">Obtenga el c\u00f3digo fuente en GitHub<\/a>y aseg\u00farese de <a href=\"https:\/\/www.couchbase.com\/blog\/es\/downloads\/\">descargar una versi\u00f3n preliminar para desarrolladores de Couchbase Server<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_why_would_i_do_this\">\u00bfPor qu\u00e9 iba a hacerlo?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Antes de empezar, quiero dedicar un poco de tiempo a la motivaci\u00f3n. Hay 3 razones principales por las que uno podr\u00eda considerar el uso de un almac\u00e9n de datos de documentos en lugar de (o adem\u00e1s de) una base de datos relacional. Tu motivaci\u00f3n puede ser una o las tres:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Velocidad<\/strong>: Couchbase Server utiliza un <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/architecture\/managed-caching-layer-architecture.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">arquitectura memory-first<\/a> que puede proporcionar un gran aumento de velocidad en comparaci\u00f3n con las bases de datos relacionales.<\/li>\n<li><strong>Escalabilidad<\/strong>: Couchbase Server es un <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/architecture\/architecture-intro.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">base de datos distribuida<\/a>que le permite ampliar (y reducir) la capacidad simplemente acumulando hardware b\u00e1sico. Las funciones integradas de Couchbase, como la autodistribuci\u00f3n, la replicaci\u00f3n y el equilibrio de carga, hacen que el escalado sea mucho m\u00e1s f\u00e1cil y fluido que el de las bases de datos relacionales.<\/li>\n<li><strong>Flexibilidad<\/strong>: Algunos datos encajan perfectamente en un modelo relacional, pero otros pueden beneficiarse de la <a href=\"https:\/\/docs.couchbase.com\/server\/6.0\/learn\/data\/document-data-model.html\">flexibilidad del uso de JSON<\/a>. A diferencia de SQL Server, el mantenimiento del esquema ya no es un problema. Con JSON: el esquema se dobla seg\u00fan tus necesidades.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Por estas y otras razones, <a href=\"https:\/\/www.couchbase.com\/blog\/es\/sql-server\/\">Gannett cambia SQL Server por Couchbase Server<\/a>. Si lo est\u00e1 considerando, definitivamente <a href=\"https:\/\/www.couchbase.com\/blog\/es\/nosql-resources\/presentations\/how-gannett-achieved-scalability-and-agility-with-nosql.html\/\">consulte la presentaci\u00f3n completa de Gannett<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>[youtube https:\/\/www.youtube.com\/watch?v=mor2p0UqZ14&amp;w=560&amp;h=315]<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Cabe se\u00f1alar que las bases de datos documentales y las bases de datos relacionales pueden ser complementarias. Tu aplicaci\u00f3n puede ser mejor servida por una, la otra, o una combinaci\u00f3n de ambas. En muchos casos, simplemente no es posible eliminar completamente las bases de datos relacionales de tu dise\u00f1o, pero una base de datos de documentos como Couchbase Server todav\u00eda puede aportar los beneficios anteriores a tu software. El resto de esta serie de blogs asumir\u00e1 que tienes experiencia con SQL Server y que est\u00e1s reemplazando, complementando o empezando un nuevo proyecto usando Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>La facilidad o dificultad de la transici\u00f3n de una aplicaci\u00f3n existente var\u00eda mucho en funci\u00f3n de una serie de factores. En algunos casos puede ser extremadamente f\u00e1cil; en otros llevar\u00e1 mucho tiempo y ser\u00e1 dif\u00edcil; en algunos casos (cada vez menos) puede que ni siquiera sea una buena idea.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_understanding_the_differences\">Comprender las diferencias<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>El primer paso consiste en comprender c\u00f3mo se modelan los datos en una base de datos documental. En una base de datos relacional, los datos suelen almacenarse en una tabla y se estructuran con claves primarias y externas. Como ejemplo sencillo, consideremos una base de datos relacional para un sitio web que tiene un carrito de la compra, as\u00ed como caracter\u00edsticas de medios sociales. (En este ejemplo, esas funciones no est\u00e1n relacionadas para simplificar las cosas).<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2017\/february\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/045_01_diagram.png\" alt=\"Relational database example diagram\" \/><\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>En una base de datos de documentos, los datos se almacenan como claves y valores. Un bucket de Couchbase contiene documentos; cada documento tiene una clave \u00fanica y un valor JSON. No hay claves externas (o, m\u00e1s exactamente, no hay restricciones de clave externa).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>He aqu\u00ed una comparaci\u00f3n de alto nivel de las caracter\u00edsticas\/nomenclatura de SQL Server en comparaci\u00f3n con Couchbase:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Tabla 1. SQL Server comparado con Couchbase<\/caption>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Servidor SQL<\/th>\n<th class=\"tableblock halign-left valign-top\">Servidor Couchbase<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Servidor<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Grupo<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Base de datos<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Cubo<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Fila(s) de tabla(s)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Documento<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Columna<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Clave\/valor JSON<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Clave principal<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Clave del documento<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Estas comparaciones son un punto de partida metaf\u00f3rico. Mirando esa tabla, puede ser tentador adoptar un enfoque simplista. \"Tengo 5 tablas, por lo tanto me limitar\u00e9 a crear 5 tipos diferentes de documentos, con un documento por fila\". Esto equivale a traducir literalmente una lengua escrita. Este enfoque puede funcionar a veces, pero no tiene en cuenta toda la potencia de una base de datos de documentos que utiliza JSON. Al igual que una traducci\u00f3n literal de una lengua escrita no tiene en cuenta el contexto cultural, los modismos y el contexto hist\u00f3rico.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Debido a la flexibilidad de JSON, los datos de una base de datos de documentos se pueden estructurar m\u00e1s como un objeto de dominio en su aplicaci\u00f3n. Por lo tanto, no tienes un desajuste de impedancia que a menudo se aborda con herramientas OR\/M como Entity Framework y NHibernate.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Hay dos enfoques principales que puedes utilizar al modelar datos en Couchbase que examinaremos m\u00e1s adelante:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Desnormalizaci\u00f3n<\/strong> - En lugar de dividir los datos entre tablas utilizando claves externas, agrupe los conceptos en un \u00fanico documento.<\/li>\n<li><strong>Referencial<\/strong> - Los conceptos tienen sus propios documentos, pero hacen referencia a otros documentos utilizando la clave de documento.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_denormalization_example\">Ejemplo de desnormalizaci\u00f3n<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Consideremos la entidad \"carrito de la compra\".<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Para representar esto en una base de datos relacional probablemente se necesitar\u00edan dos tablas: una tabla ShoppingCart y una tabla ShoppingCartItem con una clave externa a una fila en ShoppingCart.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Al crear el modelo para una base de datos de documentos, hay que decidir si se sigue modelando como dos entidades separadas (por ejemplo, un documento ShoppingCart y los correspondientes documentos ShoppingCartItem) o si se \"desnormaliza\" y se combinan una fila de ShoppingCart y fila(s) de ShoppingCartItem en un \u00fanico documento para representar un carrito de la compra.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En Couchbase, utilizando una estrategia de desnormalizaci\u00f3n, un carrito de la compra y los art\u00edculos que contiene estar\u00edan representados por un \u00fanico documento.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">{\r\n  \"usuario\": \"mgroves\",\r\n  \"dateCreated\": \"2017-02-02T15:28:11.0208157-05:00\",\r\n  \"items\": [\r\n    {\r\n      \"name\": \"BB-8 Sphero\",\r\n      \"price\": 80.18,\r\n      \"cantidad\": 1\r\n    },\r\n    {\r\n      \"name\": \"Shopkins Temporada 5\",\r\n      \"price\": 59.99,\r\n      \"quantity\": 2\r\n    }\r\n  ],\r\n  \"tipo\": \"ShoppingCart\"\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Observe que la relaci\u00f3n entre los art\u00edculos y el carro de la compra est\u00e1 ahora impl\u00edcita al estar contenidos en el mismo documento. Ya no es necesario un ID en los art\u00edculos para representar una relaci\u00f3n.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En C#, es probable que defina <code>Carrito de la compra<\/code> y <code>Art\u00edculo<\/code> para modelar estos datos:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public clase ShoppingCart\r\n{\r\n    public Guid Id { get; set; }\r\n    public string Usuario { get; set; }\r\n    public DateTime FechaCreaci\u00f3n { get; set; }\r\n    public List Items { get; set; }\r\n}\r\n\r\npublic class Elemento\r\n{\r\n    public Guid Id { get; set; }    \/\/ necesario para SQL Server, no para Couchbase\r\n    public string Nombre { get; set; }\r\n    public decimal Price { get; set; }\r\n    public int Cantidad { get; set; }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Estas clases seguir\u00edan teniendo sentido con Couchbase, as\u00ed que puedes reutilizarlas o dise\u00f1arlas de esta forma. Pero con una base de datos relacional, este dise\u00f1o no coincide de forma directa.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>De ah\u00ed la necesidad de OR\/Ms como NHibernate o Entity Framework. La forma en que el modelo anterior se puede asignar a una base de datos relacional se representa en Entity Framework* de la siguiente manera:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public class MapaCarroDeCompras : EntityTypeConfiguration\r\n{\r\n    public MapaCarroDeCompras()\r\n    {\r\n        this.HasKey(m =&gt; m.Id);\r\n\r\n        this.ToTable(\"ShoppingCart\");\r\n        this.Property(m =&gt; m.User);\r\n        this.Property(m =&gt; m.DateCreated);\r\n        this.HasMany(m =&gt; m.Items)\r\n            .WithOptional()\r\n            .HasForeignKey(m =&gt; m.ShoppingCartId);\r\n    }\r\n}\r\n\r\npublic class ShoppingCartItemMap : EntityTypeConfiguration\r\n{\r\n    public ShoppingCartItemMap()\r\n    {\r\n        this.HasKey(m =&gt; m.Id);\r\n\r\n        this.ToTable(\"ShoppingCartItems\");\r\n        this.Property(m =&gt; m.Nombre);\r\n        this.Property(m =&gt; m.Precio);\r\n        this.Property(m =&gt; m.Quantity);\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>*Otros OR\/M tendr\u00e1n asignaciones similares<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Bas\u00e1ndome en estos mapeos y en un an\u00e1lisis de los casos de uso, pude decidir que se modelar\u00eda como un \u00fanico documento en Couchbase. <code>ShoppingCartItemMap<\/code> s\u00f3lo existe para que el OR\/M sepa c\u00f3mo rellenar el <code>Art\u00edculos<\/code> propiedad en <code>Carrito de la compra<\/code>. Adem\u00e1s, es poco probable que la aplicaci\u00f3n haga lecturas del carrito de la compra sin <em>tambi\u00e9n<\/em> necesidad de leer los art\u00edculos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En un post posterior se hablar\u00e1 m\u00e1s de las OR\/M, pero por ahora puedo decir que las <code>ShoppingCartMap<\/code> y <code>ShoppingCartItemMap<\/code> no son necesarias cuando se utiliza Couchbase, y las clases <code>Id<\/code> campo de <code>Art\u00edculo<\/code> no es necesario. De hecho, el SDK .NET de Couchbase puede rellenar directamente un <code>Carrito de la compra<\/code> sin OR\/M en una sola l\u00ednea de c\u00f3digo:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public ShoppingCart GetCartById(Guid id)\r\n{\r\n    return _bucket.Get(id.ToString()).Value;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Esto no quiere decir que usar Couchbase siempre resulte en un c\u00f3digo m\u00e1s corto y f\u00e1cil de leer. Pero para ciertos casos de uso, definitivamente puede tener un impacto.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_referential_example\">Ejemplo referencial<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>No siempre es posible u \u00f3ptimo desnormalizar relaciones como la <code>Carrito de la compra<\/code> ejemplo. En muchos casos, un documento necesitar\u00e1 hacer referencia a otro documento. Dependiendo de c\u00f3mo su aplicaci\u00f3n espera hacer lecturas y escrituras, es posible que desee mantener su modelo en documentos separados mediante el uso de referencias.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Veamos un ejemplo en el que referenciar podr\u00eda ser el mejor enfoque. Supongamos que tu aplicaci\u00f3n tiene algunos elementos de redes sociales. Los usuarios pueden tener amigos, y los usuarios pueden publicar actualizaciones de texto.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Una forma de modelar esto:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Usuarios como documentos individuales<\/li>\n<li>Actualizaciones como documentos individuales que hacen referencia a un usuario<\/li>\n<li>Friends como matriz de claves dentro de un documento de usuario<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Con dos usuarios, dos actualizaciones, tendr\u00edamos 4 documentos en Couchbase con este aspecto:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">[\r\n  \/\/ Clave: \"7fc5503f-2092-4bac-8c33-65ef5b388f4b\"\r\n  {\r\n    \"amigos\": [\r\n      \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n    ],\r\n    \"name\": \"Matt Groves\",\r\n    \"tipo\": \"User\"\r\n  },\r\n\r\n  \/\/ Clave: \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n  {\r\n    \"friends\": [ ],\r\n    \"nombre\": \"Nic Raboy\",\r\n    \"tipo\": \"User\"\r\n  },\r\n\r\n  \/\/ Clave: \"5262cf62-eb10-4fdd-87ca-716321405663\"\r\n  {\r\n    \"body\": \"Nostrum eligendi aspernatur enim repellat culpa\",\r\n    \"postedDate\": \"2017-02-02T16:19:45.2792288-05:00\",\r\n    \"type\": \"Update\",\r\n    \"user\": \"7fc5503f-2092-4bac-8c33-65ef5b388f4b\"\r\n  },\r\n\r\n  \/\/ Clave: \"8d710b83-a830-4267-991e-4654671eb14f\"\r\n  {\r\n    \"body\": \"Autem occaecati quam vel. In aspernatur dolorum\",\r\n    \"postedDate\": \"2017-02-02T16:19:48.7812386-05:00\",\r\n    \"type\": \"Update\",\r\n    \"user\": \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n  }\r\n]<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Decid\u00ed modelar los \"amigos\" como una relaci\u00f3n unidireccional (como Twitter) para este ejemplo, por lo que Matt Groves tiene a Nic Raboy como amigo, pero no viceversa. (No le des demasiada importancia, Nic :).<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>La forma de modelar esto en C# podr\u00eda ser:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">clase p\u00fablica FriendbookUser\r\n{\r\n    public Guid Id { get; set; }\r\n    public string Nombre { get; set; }\r\n    public virtual Lista Amigos { get; set; }\r\n}\r\n\r\npublic class Actualizaci\u00f3n\r\n{\r\n    public Guid Id { get; set; }\r\n    public DateTime PostedDate { get; set; }\r\n    public string Cuerpo { get; set; }\r\n\r\n    public virtual FriendbookUser Usuario { get; set; }\r\n    public Guid UserId { get; set; }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>En <code>Actualizaci\u00f3n<\/code> a <code>FriendbookUsuario<\/code> puede modelarse como una <code>Gu\u00eda<\/code> o como otro <code>FriendbookUsuario<\/code> objeto. Se trata de un detalle de implementaci\u00f3n. Usted puede preferir uno, el otro, o ambos, dependiendo de sus necesidades de aplicaci\u00f3n y \/ o c\u00f3mo su OR \/ M funciona. En cualquier caso, el modelo subyacente es el mismo.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Aqu\u00ed est\u00e1 el mapeo que utilic\u00e9 para estas clases en Entity Framework. Su kilometraje puede variar, dependiendo de c\u00f3mo utilice EF u otras herramientas OR\/M. Conc\u00e9ntrate en el modelo subyacente y no en los detalles de la herramienta de mapeo OR\/M.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public class MapaDeActualizaci\u00f3n : EntityTypeConfiguration\r\n{\r\n    public UpdateMap()\r\n    {\r\n        this.HasKey(m =&gt; m.Id);\r\n\r\n        this.ToTable(\"FriendBookUpdates\");\r\n        this.Property(m =&gt; m.Body);\r\n        this.Property(m =&gt; m.PostedDate);\r\n        this.HasRequired(m =&gt; m.User)\r\n            .WithMany()\r\n            .HasForeignKey(m =&gt; m.UserId);\r\n    }\r\n}\r\n\r\npublic class FriendbookUserMap : EntityTypeConfiguration\r\n{\r\n    public FriendbookUserMap()\r\n    {\r\n        this.HasKey(m =&gt; m.Id);\r\n\r\n        this.ToTable(\"FriendBookUsers\");\r\n        this.Property(m =&gt; m.Name);\r\n        this.HasMany(t =&gt; t.Friends)\r\n            .WithMany()\r\n            .Map(m =&gt;\r\n            {\r\n                m.MapLeftKey(\"IdUsuario\");\r\n                m.MapRightKey(\"FriendUserId\");\r\n                m.ToTable(\"FriendBookUsersFriends\");\r\n            });\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Si, en lugar de almacenar estas entidades como documentos separados, aplic\u00e1ramos la misma desnormalizaci\u00f3n que en el ejemplo de la cesta de la compra e intent\u00e1ramos almacenar un usuario y las actualizaciones en un solo documento, acabar\u00edamos teniendo algunos problemas.<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Duplicaci\u00f3n de amigos<\/strong>Cada usuario almacenar\u00eda los datos de sus amigos. Esto no es sostenible, porque ahora la informaci\u00f3n de un usuario estar\u00eda almacenada en m\u00faltiples lugares en lugar de tener una \u00fanica fuente de verdad (a diferencia del carrito de la compra, donde tener el mismo art\u00edculo en m\u00e1s de un carrito probablemente no tiene ning\u00fan sentido de dominio). Esto podr\u00eda estar bien cuando se utiliza Couchbase como una cach\u00e9, pero no como un almac\u00e9n de datos primario.<\/li>\n<li><strong>Tama\u00f1o de las actualizaciones<\/strong>: Durante un periodo de uso regular, un usuario individual podr\u00eda publicar cientos o miles de actualizaciones. Esto podr\u00eda dar lugar a un documento muy grande que podr\u00eda ralentizar las operaciones de E\/S. Esto se puede mitigar con la herramienta de Couchbase <a href=\"https:\/\/www.couchbase.com\/blog\/es\/subdoc-explained\/\">subdocumento API<\/a>pero ten en cuenta que Couchbase tiene un l\u00edmite de 20 MB por documento.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Nota: Aqu\u00ed tambi\u00e9n hay un problema de N+1 (amigos de amigos, etc.), pero no voy a dedicar tiempo a resolverlo. Es un problema que no es exclusivo de ninguna de las dos bases de datos.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Adem\u00e1s, puede que cuando la aplicaci\u00f3n lea o escriba un usuario no necesite leer o escribir amigos y actualizaciones. Y, al escribir una actualizaci\u00f3n, no es probable que la aplicaci\u00f3n necesite actualizar un usuario. Dado que estas entidades a menudo pueden ser le\u00eddas\/escritas por s\u00ed solas, eso indica que necesitan ser modeladas como documentos separados.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Observe la matriz en el <code>Amigos<\/code> del documento de usuario y el valor del campo <code>Usuario<\/code> del documento de actualizaci\u00f3n. Estos valores se pueden utilizar para recuperar los documentos asociados. M\u00e1s adelante en este post, voy a discutir c\u00f3mo hacerlo con operaciones clave\/valor y c\u00f3mo hacerlo con N1QL.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En resumen, hay dos formas de modelar datos en una base de datos de documentos. En el ejemplo de la cesta de la compra se utiliz\u00f3 <strong>objetos anidados<\/strong>mientras que el ejemplo de las redes sociales <strong>documentos separados<\/strong>. En esos ejemplos, la elecci\u00f3n era relativamente sencilla. Cuando tomes tus propias decisiones de modelado, aqu\u00ed tienes una pr\u00e1ctica hoja de trucos:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Tabla 2. Ficha de datos de modelizaci\u00f3n<\/caption>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Si...<\/th>\n<th class=\"tableblock halign-left valign-top\">Entonces considera...<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">La relaci\u00f3n es de 1 a 1 o de 1 a muchos<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos anidados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">La relaci\u00f3n es muchos-a-1 o muchos-a-muchos<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Documentos separados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Los datos le\u00eddos son en su mayor\u00eda campos padre<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Documento aparte<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Los datos le\u00eddos son en su mayor\u00eda campos padre + hijo<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos anidados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Las lecturas de datos son en su mayor\u00eda parentales <em>o<\/em> ni\u00f1o (no ambos)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Documentos separados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Las escrituras de datos son en su mayor\u00eda de los padres <em>y<\/em> ni\u00f1o (ambos)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos anidados<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"sect2\">\n<h3 id=\"_key_value_operations\">Operaciones clave\/valor<\/h3>\n<div class=\"paragraph\">\n<p>Para obtener documento(s) en Couchbase, la forma m\u00e1s sencilla y r\u00e1pida es pedirlos por clave. Una vez que tenga uno de los <code>FriendbookUsuario<\/code> documentos anteriores, puede ejecutar otra operaci\u00f3n para obtener los documentos asociados. Por ejemplo, podr\u00eda pedirle a Couchbase que me diera los documentos de las claves 2, 3 y 1031 (como una operaci\u00f3n por lotes). Esto me dar\u00eda los documentos de cada amigo. Luego puedo repetir eso para <code>Actualizaciones<\/code>etc.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>El beneficio de esto es la velocidad: las operaciones clave\/valor son muy r\u00e1pidas en Couchbase, y probablemente estar\u00e1s obteniendo valores directamente de la RAM.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>El inconveniente es que implica al menos dos operaciones (obtener el documento FriendbookUser y, a continuaci\u00f3n, obtener las actualizaciones). As\u00ed que esto puede implicar un poco de codificaci\u00f3n adicional. Tambi\u00e9n puede requerir que pienses m\u00e1s detenidamente en c\u00f3mo construyes las claves de los documentos (m\u00e1s sobre esto m\u00e1s adelante).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_n1ql\">N1QL<\/h3>\n<div class=\"paragraph\">\n<p>En Couchbase, tienes la posibilidad de escribir consultas usando N1QL, que es SQL para JSON. Esto incluye el <code>\u00daNASE A<\/code> palabra clave. Esto me permite, por ejemplo, escribir una consulta para obtener las 10 \u00faltimas actualizaciones y los usuarios que les corresponden.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public Lista GetTenLatestUpdates()\r\n{\r\n    var n1ql = @\"SELECT up.body, up.postedDate, { `id': META(u).id, u.name} COMO `user`.\r\n        FROM `sqltocb` up\r\n        JOIN `sqltocb` u ON KEYS up.`user`\r\n        WHERE up.type = 'Update'\r\n        ORDER BY STR_TO_MILLIS(up.postedDate) DESC\r\n        LIMIT 10;\";\r\n    var query = QueryRequest.Create(n1ql);\r\n    query.ScanConsistency(ScanConsistency.RequestPlus);\r\n    var result = _bucket.Query(query);\r\n    return resultado.Filas;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>El resultado de esta consulta ser\u00eda:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">[\r\n  {\r\n    \"body\": \"Autem occaecati quam vel. In aspernatur dolorum\",\r\n    \"postedDate\": \"2017-02-02T16:19:48.7812386-05:00\",\r\n    \"user\": {\r\n      \"id\": \"c5f05561-9fbf-4ab0-b68f-e392267c0703\",\r\n      \"name\": \"Bob Johnson\"\r\n    }\r\n  },\r\n  {\r\n    \"body\": \"Nostrum eligendi aspernatur enim repellat culpa eligendi maiores et\",\r\n    \"postedDate\": \"2017-02-02T16:19:45.2792288-05:00\",\r\n    \"user\": {\r\n      \"id\": \"7fc5503f-2092-4bac-8c33-65ef5b388f4b\",\r\n      \"name\": \"Steve Oberbrunner\"\r\n    }\r\n  },\r\n\r\n  \/\/ ... etc ...\r\n]<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>N1QL le permite tener una gran flexibilidad en la recuperaci\u00f3n de datos. No tengo que estar restringido al uso de claves. Tambi\u00e9n es f\u00e1cil de aprender, ya que es un superconjunto de SQL con el que los usuarios de SQL Server se sentir\u00e1n c\u00f3modos r\u00e1pidamente. Sin embargo, la contrapartida es que la indexaci\u00f3n es importante. Incluso m\u00e1s que la indexaci\u00f3n de SQL Server. Si escribiera una consulta en la base de datos <code>Nombre<\/code> por ejemplo, deber\u00eda tener un \u00edndice como<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\">CREATE INDEX IX_Name ON `SocialMedia` (Nombre) USING GSI;<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>De lo contrario, la consulta no se ejecutar\u00e1 (si no tiene indexaci\u00f3n) o no tendr\u00e1 rendimiento (si s\u00f3lo tiene un \u00edndice primario creado).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/data-modeling\/entity-relationship-doc-design.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Hay pros y contras en la decisi\u00f3n de utilizar o no la referenciaci\u00f3n<\/a>. Los valores en <code>amigos<\/code> y <code>usuario<\/code> son similares a las claves for\u00e1neas, en el sentido de que hacen referencia a otro documento. Pero no hay imposici\u00f3n de valores por parte de Couchbase. La gesti\u00f3n de estas claves debe ser manejada adecuadamente por la aplicaci\u00f3n. Adem\u00e1s, mientras Couchbase provee transacciones ACID para operaciones de un solo documento, no hay transacciones ACID multi-documento disponibles.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Hay formas de abordar estas advertencias en la capa de aplicaci\u00f3n que se tratar\u00e1n con m\u00e1s detalle en posteriores entradas de esta serie, as\u00ed que permanezca atento.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_key_design_and_document_differentiation\">Dise\u00f1o clave y diferenciaci\u00f3n de documentos<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>En las bases de datos relacionales, las filas de datos (normalmente, no siempre) corresponden a una clave primaria, que suele ser un n\u00famero entero o un Guid, y a veces una clave compuesta. Estas claves no tienen necesariamente ning\u00fan significado: s\u00f3lo sirven para identificar una fila dentro de una tabla. Por ejemplo, dos filas de datos en dos tablas diferentes pueden tener la misma clave (un valor entero de 123, por ejemplo), pero eso no significa necesariamente que los datos est\u00e9n relacionados. Esto se debe a que el esquema aplicado por las bases de datos relacionales a menudo transmite un significado por s\u00ed mismo (por ejemplo, el nombre de una tabla).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>En bases de datos de documentos como Couchbase, no hay nada equivalente a una tabla, per se. Cada documento en un bucket debe tener una clave \u00fanica. Pero un bucket puede tener una variedad de documentos en \u00e9l. Por lo tanto, a menudo es conveniente encontrar una manera de diferenciar los documentos dentro de un cubo.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_meaningful_keys\">Claves significativas<\/h3>\n<div class=\"paragraph\">\n<p>Por ejemplo, es perfectamente posible tener un <code>FriendbookUsuario<\/code> con una clave de <code>123<\/code>y un <code>Actualizaci\u00f3n<\/code> con una clave de <code>456<\/code>. Sin embargo, ser\u00eda conveniente a\u00f1adir m\u00e1s informaci\u00f3n sem\u00e1ntica a la clave. En lugar de <code>123<\/code>utilice una clave de <code>AmigoUsuario::123<\/code>. Entre las ventajas de incluir informaci\u00f3n sem\u00e1ntica en su clave figuran las siguientes:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Legibilidad<\/strong>: De un vistazo se puede saber para qu\u00e9 sirve un documento.<\/li>\n<li><strong>Referenciabilidad<\/strong>: Si tiene un <code>AmigoUsuario::123<\/code> documento, entonces podr\u00eda tener otro documento con una clave <code>FriendbookUser::123::Actualizaciones<\/code> que tiene una asociaci\u00f3n impl\u00edcita.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Si piensas utilizar N1QL, puede que no necesites que las claves tengan tanto significado sem\u00e1ntico. En t\u00e9rminos de rendimiento, cuanto m\u00e1s corta es la clave, m\u00e1s de ellas pueden almacenarse en RAM. As\u00ed que s\u00f3lo utilice este patr\u00f3n si planea hacer un uso intensivo de operaciones clave\/valor en lugar de consultas N1QL.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_discriminator_fields\">Campos discriminadores<\/h3>\n<div class=\"paragraph\">\n<p>Cuando se utiliza N1QL, otra t\u00e1ctica que se puede utilizar adem\u00e1s o en lugar de claves significativas es a\u00f1adir campo(s) a un documento que se utilizan para diferenciar el documento. Esto suele implementarse como <code>tipo<\/code> dentro de un documento.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">{\r\n    \"direcci\u00f3n\" : \"1800 Brown Rd\",\r\n    \"ciudad\" : \"Groveport\",\r\n    \"estado\" : \"OH\",\r\n    \"type\" : \"address\"\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>No hay nada m\u00e1gico en el <code>tipo<\/code> campo. No es una palabra reservada dentro de un documento y no es tratada especialmente por Couchbase Server. Podr\u00eda llamarse <code>tipo de documento<\/code>, <code>elTipo<\/code>etc. Pero puede ser \u00fatil dentro de su aplicaci\u00f3n cuando se utiliza N1QL para consultar documentos de un determinado tipo.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-SQL\">SELECT d.*\r\nFROM `default` d\r\nWHERE d.type = 'direcci\u00f3n'<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Incluso puedes ir un paso m\u00e1s all\u00e1 y a\u00f1adir un objeto incrustado a tus documentos para que act\u00fae como una especie de \"metadatos\" de imitaci\u00f3n:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">{\r\n    \"direcci\u00f3n\" : \"1800 Brown Rd\",\r\n    \"ciudad\" : \"Groveport\",\r\n    \"estado\" : \"OH\",\r\n    \"documentInfo\" : {\r\n        \"tipo\" : \"direcci\u00f3n\",\r\n        \"lastUpdated\" : \"1\/29\/2017 1:31:10 PM\",\r\n        \"lastUpdatedBy\" : \"mgroves\"\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Esto puede ser excesivo para algunas aplicaciones. Es similar a un patr\u00f3n que he visto en bases de datos relacionales: una tabla \"ra\u00edz\" para simular la herencia dentro de una base de datos relacional, o quiz\u00e1s los mismos campos a\u00f1adidos a cada tabla.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion_of_part_1\">Conclusi\u00f3n de la 1\u00aa parte<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>En esta entrada del blog se trat\u00f3 el modelado de datos mediante desnormalizaci\u00f3n, el modelado de datos mediante referenciaci\u00f3n, el dise\u00f1o de claves y la discriminaci\u00f3n de campos. El modelado de datos en una base de datos de documentos es un proceso de pensamiento, algo as\u00ed como una forma de arte, y no un proceso mec\u00e1nico. No existe una receta sobre c\u00f3mo modelar los datos en una base de datos de documentos: depende en gran medida de c\u00f3mo interact\u00fae la aplicaci\u00f3n con los datos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Puede obtener el <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">c\u00f3digo fuente de toda la serie de blogs en GitHub ahora<\/a>partes del cual se presentaron en esta entrada del blog. Si tienes preguntas sobre diversas partes de ese c\u00f3digo, no dudes en dejar un comentario a continuaci\u00f3n o abrir una incidencia en GitHub.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Permanezca atento al pr\u00f3ximo blog de la serie, en el que se hablar\u00e1 de datos y migraci\u00f3n de datos.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Si tiene alguna pregunta, deje un comentario a continuaci\u00f3n, <a href=\"https:\/\/twitter.com\/mgroves\">p\u00f3ngase en contacto conmigo en Twitter<\/a>o utilice el bot\u00f3n <a href=\"https:\/\/www.couchbase.com\/blog\/es\/forums\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Foros de Couchbase<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>In this series of blog posts, I\u2019m going to lay out the considerations when moving to a document database when you have a relational background. Specifically, Microsoft SQL Server as compared to Couchbase Server. In three parts, I\u2019m going to [&hellip;]<\/p>","protected":false},"author":71,"featured_media":2574,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,1814,10126,1815,10127,1816,1819,1812],"tags":[1447,1806,1807,1805,1556],"ppma_author":[8937],"class_list":["post-2521","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-application-design","category-asp-dotnet","category-best-practices-and-tutorials","category-c-sharp","category-couchbase-server","category-data-modeling","category-n1ql-query","tag-data-modeling","tag-entity-framework","tag-nhibernate","tag-or-m","tag-sql-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Data Modeling in SQL Server: Making the Move to Couchbase<\/title>\n<meta name=\"description\" content=\"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to 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\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Moving from SQL Server to Couchbase Part 1: Data Modeling\" \/>\n<meta property=\"og:description\" content=\"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to Couchbase Server.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-02-03T16:05:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:57:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2048\" \/>\n\t<meta property=\"og:image:height\" content=\"949\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matthew Groves\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mgroves\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matthew Groves\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\"},\"author\":{\"name\":\"Matthew Groves\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58\"},\"headline\":\"Moving from SQL Server to Couchbase Part 1: Data Modeling\",\"datePublished\":\"2017-02-03T16:05:12+00:00\",\"dateModified\":\"2025-06-14T03:57:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\"},\"wordCount\":2849,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\",\"keywords\":[\"Data Modeling\",\"Entity Framework\",\"NHibernate\",\"OR\/M\",\"SQL Server\"],\"articleSection\":[\".NET\",\"Application Design\",\"ASP.NET\",\"Best Practices and Tutorials\",\"C#\",\"Couchbase Server\",\"Data Modeling\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\",\"name\":\"Data Modeling in SQL Server: Making the Move to Couchbase\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\",\"datePublished\":\"2017-02-03T16:05:12+00:00\",\"dateModified\":\"2025-06-14T03:57:15+00:00\",\"description\":\"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to Couchbase Server.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg\",\"width\":2048,\"height\":949,\"caption\":\"Geese migration licensed through Creative Commons https:\/\/commons.wikimedia.org\/wiki\/File:BrantaLeucopsisMigration.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Moving from SQL Server to Couchbase Part 1: Data Modeling\"}]},{\"@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\/3929663e372020321b0152dc4fa65a58\",\"name\":\"Matthew Groves\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/ba51e6aacc53995c323a634e4502ef54\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g\",\"caption\":\"Matthew Groves\"},\"description\":\"Matthew D. Groves is a guy who loves to code. It doesn't matter if it's C#, jQuery, or PHP: he'll submit pull requests for anything. He has been coding professionally ever since he wrote a QuickBASIC point-of-sale app for his parent's pizza shop back in the 90s. He currently works as a Senior Product Marketing Manager for Couchbase. His free time is spent with his family, watching the Reds, and getting involved in the developer community. He is the author of AOP in .NET, Pro Microservices in .NET, a Pluralsight author, and a Microsoft MVP.\",\"sameAs\":[\"https:\/\/crosscuttingconcerns.com\",\"https:\/\/x.com\/mgroves\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/matthew-groves\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Data Modeling in SQL Server: Making the Move to Couchbase","description":"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to 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\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","og_locale":"es_MX","og_type":"article","og_title":"Moving from SQL Server to Couchbase Part 1: Data Modeling","og_description":"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to Couchbase Server.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","og_site_name":"The Couchbase Blog","article_published_time":"2017-02-03T16:05:12+00:00","article_modified_time":"2025-06-14T03:57:15+00:00","og_image":[{"width":2048,"height":949,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","type":"image\/jpeg"}],"author":"Matthew Groves","twitter_card":"summary_large_image","twitter_creator":"@mgroves","twitter_misc":{"Written by":"Matthew Groves","Est. reading time":"13 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/"},"author":{"name":"Matthew Groves","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58"},"headline":"Moving from SQL Server to Couchbase Part 1: Data Modeling","datePublished":"2017-02-03T16:05:12+00:00","dateModified":"2025-06-14T03:57:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/"},"wordCount":2849,"commentCount":4,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","keywords":["Data Modeling","Entity Framework","NHibernate","OR\/M","SQL Server"],"articleSection":[".NET","Application Design","ASP.NET","Best Practices and Tutorials","C#","Couchbase Server","Data Modeling","SQL++ \/ N1QL Query"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","url":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","name":"Data Modeling in SQL Server: Making the Move to Couchbase","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","datePublished":"2017-02-03T16:05:12+00:00","dateModified":"2025-06-14T03:57:15+00:00","description":"This post explains how to move a document database when you have a relational background. Specifically, Microsoft SQL Server compared to Couchbase Server.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/geese-migration.jpg","width":2048,"height":949,"caption":"Geese migration licensed through Creative Commons https:\/\/commons.wikimedia.org\/wiki\/File:BrantaLeucopsisMigration.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Moving from SQL Server to Couchbase Part 1: Data Modeling"}]},{"@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\/3929663e372020321b0152dc4fa65a58","name":"Matthew Groves","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/ba51e6aacc53995c323a634e4502ef54","url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","caption":"Matthew Groves"},"description":"A Matthew D. Groves le encanta programar. No importa si se trata de C#, jQuery o PHP: enviar\u00e1 pull requests para cualquier cosa. Lleva codificando profesionalmente desde que escribi\u00f3 una aplicaci\u00f3n de punto de venta en QuickBASIC para la pizzer\u00eda de sus padres, all\u00e1 por los a\u00f1os noventa. Actualmente trabaja como Director de Marketing de Producto para Couchbase. Su tiempo libre lo pasa con su familia, viendo a los Reds y participando en la comunidad de desarrolladores. Es autor de AOP in .NET, Pro Microservices in .NET, autor de Pluralsight y MVP de Microsoft.","sameAs":["https:\/\/crosscuttingconcerns.com","https:\/\/x.com\/mgroves"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/matthew-groves\/"}]}},"authors":[{"term_id":8937,"user_id":71,"is_guest":0,"slug":"matthew-groves","display_name":"Matthew Groves","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/70feb1b28a099ad0112b8d21fe1e81e1a4524beed3e20b7f107d5370e85a07ab?s=96&d=mm&r=g","first_name":"Matthew","last_name":"Groves","user_url":"https:\/\/crosscuttingconcerns.com","author_category":"","description":"A Matthew D. Groves le encanta programar.  No importa si se trata de C#, jQuery o PHP: enviar\u00e1 pull requests para cualquier cosa.  Lleva codificando profesionalmente desde que escribi\u00f3 una aplicaci\u00f3n de punto de venta en QuickBASIC para la pizzer\u00eda de sus padres, all\u00e1 por los a\u00f1os noventa.  Actualmente trabaja como Director de Marketing de Producto para Couchbase. Su tiempo libre lo pasa con su familia, viendo a los Reds y participando en la comunidad de desarrolladores.  Es autor de AOP in .NET, Pro Microservices in .NET, autor de Pluralsight y MVP de Microsoft."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2521","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\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=2521"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/2521\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/2574"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=2521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=2521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=2521"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=2521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}