{"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\/pt\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","title":{"rendered":"Mudan\u00e7a do SQL Server para o Couchbase Parte 1: Modelagem de dados"},"content":{"rendered":"<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Nesta s\u00e9rie de postagens do blog, apresentarei as considera\u00e7\u00f5es sobre a mudan\u00e7a para um banco de dados de documentos quando voc\u00ea tem um hist\u00f3rico relacional. Especificamente, o Microsoft SQL Server em compara\u00e7\u00e3o com o <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/developers\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Servidor Couchbase<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Em tr\u00eas partes, abordarei o assunto:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Modelagem de dados (esta postagem do blog)<\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sql-server-couchbase-data-migration\/\">Os dados em si<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/pt\/moving-sql-server-couchbase-app-migration\/\">Aplicativos que usam os dados<\/a><\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>O objetivo \u00e9 estabelecer algumas diretrizes gerais que podem ser aplicadas ao planejamento e ao design do seu aplicativo.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Se voc\u00ea quiser acompanhar, criei um aplicativo que demonstra o Couchbase e o SQL Server lado a lado. <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">Obtenha o c\u00f3digo-fonte no GitHub<\/a>e certifique-se de <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/downloads\/\">Fa\u00e7a o download de uma pr\u00e9via para desenvolvedores do Couchbase Server<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_why_would_i_do_this\">Por que eu faria isso?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Antes de come\u00e7armos, gostaria de falar um pouco sobre a motiva\u00e7\u00e3o. H\u00e1 tr\u00eas motivos principais pelos quais algu\u00e9m pode considerar o uso de um armazenamento de dados de documentos em vez de (ou al\u00e9m de) um banco de dados relacional. Sua motiva\u00e7\u00e3o pode ser uma ou todas as tr\u00eas:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Velocidade<\/strong>: O Couchbase Server usa um <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\">arquitetura memory-first<\/a> que pode proporcionar um grande aumento de velocidade em compara\u00e7\u00e3o com um banco de dados relacional<\/li>\n<li><strong>Escalabilidade<\/strong>: O Couchbase Server \u00e9 um <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/architecture\/architecture-intro.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">banco de dados distribu\u00eddo<\/a>que permite que voc\u00ea aumente (e diminua) a capacidade simplesmente acumulando hardware de commodity. Os recursos incorporados do Couchbase, como auto-sharding, replica\u00e7\u00e3o e balanceamento de carga, tornam o dimensionamento muito mais suave e f\u00e1cil do que os bancos de dados relacionais.<\/li>\n<li><strong>Flexibilidade<\/strong>: Alguns dados se encaixam perfeitamente em um modelo relacional, mas alguns dados podem se beneficiar do modelo relacional. <a href=\"https:\/\/docs.couchbase.com\/server\/6.0\/learn\/data\/document-data-model.html\">flexibilidade do uso de JSON<\/a>. Ao contr\u00e1rio do SQL Server, a manuten\u00e7\u00e3o do esquema n\u00e3o \u00e9 mais um problema. Com o JSON: o esquema se dobra conforme sua necessidade.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Por esses e outros motivos, <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/sql-server\/\">A Gannett mudou do SQL Server para o Couchbase Server<\/a>. Se estiver pensando em fazer isso, definitivamente <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/nosql-resources\/presentations\/how-gannett-achieved-scalability-and-agility-with-nosql.html\/\">Confira a apresenta\u00e7\u00e3o completa da 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>Deve-se observar que os bancos de dados de documentos e os bancos de dados relacionais podem ser complementares. Seu aplicativo pode ser melhor atendido por um, por outro ou por uma combina\u00e7\u00e3o de ambos. Em muitos casos, simplesmente n\u00e3o \u00e9 poss\u00edvel remover completamente os bancos de dados relacionais do seu projeto, mas um banco de dados de documentos como o Couchbase Server ainda pode trazer os benef\u00edcios acima para o seu software. O restante desta s\u00e9rie do blog pressup\u00f5e que voc\u00ea tenha experi\u00eancia com o SQL Server e esteja substituindo, complementando ou iniciando um novo projeto greenfield usando o Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A facilidade ou a dificuldade de fazer a transi\u00e7\u00e3o de um aplicativo existente varia muito com base em v\u00e1rios fatores. Em alguns casos, pode ser extremamente f\u00e1cil; em outros, ser\u00e1 demorado e dif\u00edcil; em alguns casos (em n\u00famero cada vez menor), pode nem ser uma boa ideia.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_understanding_the_differences\">Entendendo as diferen\u00e7as<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>A primeira etapa \u00e9 entender como os dados s\u00e3o modelados em um banco de dados de documentos. Em um banco de dados relacional, os dados s\u00e3o normalmente armazenados em uma tabela e recebem uma estrutura com chaves prim\u00e1rias e estrangeiras. Como um exemplo simples, vamos considerar um banco de dados relacional para um site que tenha um carrinho de compras e recursos de m\u00eddia social. (Neste exemplo, esses recursos n\u00e3o est\u00e3o relacionados para manter as coisas simples).<\/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>Em um banco de dados de documentos, os dados s\u00e3o armazenados como chaves e valores. Um bucket do Couchbase cont\u00e9m documentos; cada documento tem uma chave exclusiva e um valor JSON. N\u00e3o h\u00e1 chaves estrangeiras (ou, mais precisamente, n\u00e3o h\u00e1 restri\u00e7\u00f5es de chave estrangeira).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 uma compara\u00e7\u00e3o de alto n\u00edvel dos recursos\/nomea\u00e7\u00e3o do SQL Server em rela\u00e7\u00e3o ao Couchbase:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Tabela 1. SQL Server comparado ao Couchbase<\/caption>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">SQL Server<\/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\">Aglomerado<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Banco de dados<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Balde<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Linha(s) da(s) tabela(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\">Coluna<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Chave\/valor JSON<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Chave prim\u00e1ria<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Chave do documento<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Essas compara\u00e7\u00f5es s\u00e3o um ponto de partida metaf\u00f3rico. Olhando para essa tabela, pode ser tentador adotar uma abordagem simplista. \"Tenho 5 tabelas, portanto, vou criar 5 tipos diferentes de documentos, com um documento por linha.\" Isso \u00e9 o equivalente a traduzir literalmente um idioma escrito. Essa abordagem pode funcionar \u00e0s vezes, mas n\u00e3o leva em conta todo o poder de um banco de dados de documentos que usa JSON. Assim como uma tradu\u00e7\u00e3o literal de um idioma escrito n\u00e3o leva em conta o contexto cultural, as express\u00f5es idiom\u00e1ticas e o contexto hist\u00f3rico.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Devido \u00e0 flexibilidade do JSON, os dados em um banco de dados de documentos podem ser estruturados mais como um objeto de dom\u00ednio em seu aplicativo. Portanto, voc\u00ea n\u00e3o tem uma incompatibilidade de imped\u00e2ncia que geralmente \u00e9 resolvida por ferramentas de OR\/M como Entity Framework e NHibernate.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>H\u00e1 duas abordagens principais que voc\u00ea pode usar ao modelar dados no Couchbase e que examinaremos mais detalhadamente:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Desnormaliza\u00e7\u00e3o<\/strong> - Em vez de dividir os dados entre tabelas usando chaves estrangeiras, agrupe os conceitos em um \u00fanico documento.<\/li>\n<li><strong>Referencial<\/strong> - Os conceitos recebem seus pr\u00f3prios documentos, mas fazem refer\u00eancia a outros documentos usando a chave do documento.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_denormalization_example\">Exemplo de desnormaliza\u00e7\u00e3o<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Vamos considerar a entidade \"carrinho de compras\".<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Para representar isso em um banco de dados relacional, provavelmente seriam necess\u00e1rias duas tabelas: uma tabela ShoppingCart e uma tabela ShoppingCartItem com uma chave estrangeira para uma linha no ShoppingCart.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Ao criar o modelo para um banco de dados de documentos, \u00e9 preciso decidir se continuaremos a model\u00e1-lo como duas entidades separadas (por exemplo, um documento de carrinho de compras e os documentos correspondentes de item de carrinho de compras) ou se \"desnormalizaremos\" e combinaremos uma linha de ShoppingCart e linha(s) de ShoppingCartItem em um \u00fanico documento para representar um carrinho de compras.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>No Couchbase, usando uma estrat\u00e9gia de desnormaliza\u00e7\u00e3o, um carrinho de compras e os itens nele contidos seriam representados por um \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  \"user\": \"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      \"quantity\" (quantidade): 1\r\n    },\r\n    {\r\n      \"name\": \"Shopkins Season 5\",\r\n      \"price\": 59.99,\r\n      \"quantity\": 2\r\n    }\r\n  ],\r\n  \"type\": \"ShoppingCart\"\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Observe que o relacionamento entre os itens e o carrinho de compras agora est\u00e1 impl\u00edcito no fato de estarem contidos no mesmo documento. N\u00e3o h\u00e1 mais necessidade de um ID nos itens para representar um relacionamento.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Em C#, voc\u00ea provavelmente definiria <code>ShoppingCart<\/code> e <code>Item<\/code> para modelar esses dados:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">classe p\u00fablica ShoppingCart\r\n{\r\n    public Guid Id { get; set; }\r\n    public string User { get; set; }\r\n    public DateTime DateCreated { get; set; }\r\n    public List Items { get; set; }\r\n}\r\n\r\npublic class Item\r\n{\r\n    public Guid Id { get; set; }    \/\/ necess\u00e1rio para o SQL Server, n\u00e3o para o Couchbase\r\n    public string Name { get; set; }\r\n    public decimal Price { get; set; }\r\n    public int Quantity { get; set; }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Essas classes ainda fariam sentido com o Couchbase, portanto, voc\u00ea pode reutiliz\u00e1-las ou projet\u00e1-las dessa forma. Por\u00e9m, com um banco de dados relacional, esse design n\u00e3o corresponde diretamente.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Da\u00ed a necessidade de OR\/Ms como NHibernate ou Entity Framework. A maneira como o modelo acima pode ser mapeado para um banco de dados relacional \u00e9 representada no Entity Framework* da seguinte forma:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public class ShoppingCartMap : EntityTypeConfiguration\r\n{\r\n    public ShoppingCartMap()\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); this.Property(m =&gt; m.User);\r\n        this.Property(m =&gt; m.DateCreated); { 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.Name);\r\n        this.Property(m =&gt; m.Price);\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>*Outras OR\/Ms ter\u00e3o mapeamentos semelhantes<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Com base nesses mapeamentos e em uma an\u00e1lise dos casos de uso, eu poderia decidir que ele seria modelado como um \u00fanico documento no Couchbase. <code>ShoppingCartItemMap<\/code> s\u00f3 existe para que o OR\/M saiba como preencher o <code>Itens<\/code> propriedade em <code>ShoppingCart<\/code>. Al\u00e9m disso, \u00e9 improv\u00e1vel que o aplicativo fa\u00e7a leituras do carrinho de compras sem <em>tamb\u00e9m<\/em> necessidade de ler os itens.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Em uma postagem posterior, as OR\/Ms ser\u00e3o discutidas mais detalhadamente, mas, por enquanto, posso dizer que a <code>ShoppingCartMap<\/code> e <code>ShoppingCartItemMap<\/code> n\u00e3o s\u00e3o necess\u00e1rias ao usar o Couchbase, e as classes <code>Id<\/code> campo de <code>Item<\/code> n\u00e3o \u00e9 necess\u00e1rio. De fato, o SDK do Couchbase .NET pode preencher diretamente um <code>ShoppingCart<\/code> sem um OR\/M em uma \u00fanica linha 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>Isso n\u00e3o quer dizer que o uso do Couchbase sempre resultar\u00e1 em c\u00f3digos mais curtos e f\u00e1ceis de ler. Mas, para determinados casos de uso, isso pode ter um impacto definitivo.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_referential_example\">Exemplo de refer\u00eancia<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Nem sempre \u00e9 poss\u00edvel ou ideal desnormalizar rela\u00e7\u00f5es como a <code>ShoppingCart<\/code> exemplo. Em muitos casos, um documento precisar\u00e1 fazer refer\u00eancia a outro documento. Dependendo de como seu aplicativo espera fazer leituras e grava\u00e7\u00f5es, talvez voc\u00ea queira manter seu modelo em documentos separados usando refer\u00eancias.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Vamos dar uma olhada em um exemplo em que a refer\u00eancia pode ser a melhor abordagem. Suponha que seu aplicativo tenha alguns elementos de m\u00eddia social. Os usu\u00e1rios podem ter amigos e podem publicar atualiza\u00e7\u00f5es de texto.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Uma maneira de modelar isso:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Usu\u00e1rios como documentos individuais<\/li>\n<li>Atualiza\u00e7\u00f5es como documentos individuais que fazem refer\u00eancia a um usu\u00e1rio<\/li>\n<li>Amigos como uma matriz de chaves em um documento do usu\u00e1rio<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Com dois usu\u00e1rios e duas atualiza\u00e7\u00f5es, ter\u00edamos 4 documentos no Couchbase com a seguinte apar\u00eancia:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">[\r\n  \/\/ Chave: \"7fc5503f-2092-4bac-8c33-65ef5b388f4b\"\r\n  {\r\n    \"friends\": [\r\n      \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n    ],\r\n    \"name\": \"Matt Groves\",\r\n    \"type\": \"User\" (Usu\u00e1rio)\r\n  },\r\n\r\n  \/\/ Chave: \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n  {\r\n    \"friends\": [ ],\r\n    \"name\": \"Nic Raboy\",\r\n    \"type\": \"User\" (Usu\u00e1rio)\r\n  },\r\n\r\n  \/\/ Chave: \"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\" (Atualiza\u00e7\u00e3o),\r\n    \"user\": \"7fc5503f-2092-4bac-8c33-65ef5b388f4b\"\r\n  },\r\n\r\n  \/\/ Chave: \"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\" (Atualiza\u00e7\u00e3o),\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>Decidi modelar \"amigos\" como um relacionamento unidirecional (como o Twitter) para este exemplo, e \u00e9 por isso que Matt Groves tem Nic Raboy como amigo, mas n\u00e3o vice-versa. (N\u00e3o d\u00ea muita import\u00e2ncia a isso, Nic :).<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A maneira de modelar isso no C# poderia ser:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">classe p\u00fablica FriendbookUser\r\n{\r\n    public Guid Id { get; set; }\r\n    public string Name { get; set; }\r\n    public virtual List Friends { get; set; }\r\n}\r\n\r\npublic class Update\r\n{\r\n    public Guid Id { get; set; }\r\n    public DateTime PostedDate { get; set; }\r\n    public string Body { get; set; }\r\n\r\n    public virtual FriendbookUser User { get; set; }\r\n    public Guid UserId { get; set; }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><em>O <code>Atualiza\u00e7\u00e3o<\/code> para <code>Usu\u00e1rio do Friendbook<\/code> pode ser modelado como um <code>Guia<\/code> ou como outro <code>Usu\u00e1rio do Friendbook<\/code> objeto. Esse \u00e9 um detalhe de implementa\u00e7\u00e3o. Voc\u00ea pode preferir um, o outro ou ambos, dependendo das necessidades do seu aplicativo e\/ou de como o seu OR\/M funciona. Em ambos os casos, o modelo subjacente \u00e9 o mesmo.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Aqui est\u00e1 o mapeamento que usei para essas classes no Entity Framework. Sua milhagem pode variar, dependendo de como voc\u00ea usa o EF ou outras ferramentas de OR\/M. Concentre-se no modelo subjacente e n\u00e3o nos detalhes da ferramenta de mapeamento de 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 UpdateMap : 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(\"UserId\");\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>Se, em vez de armazenar essas entidades como documentos separados, aplic\u00e1ssemos a mesma desnormaliza\u00e7\u00e3o do exemplo do carrinho de compras e tent\u00e1ssemos armazenar um usu\u00e1rio e as atualiza\u00e7\u00f5es em um \u00fanico documento, ter\u00edamos alguns problemas.<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Duplica\u00e7\u00e3o de amigos<\/strong>Cada usu\u00e1rio armazenaria os detalhes de seus amigos. Isso n\u00e3o \u00e9 sustent\u00e1vel, porque agora as informa\u00e7\u00f5es de um usu\u00e1rio seriam armazenadas em v\u00e1rios locais, em vez de ter uma \u00fanica fonte de verdade (ao contr\u00e1rio do carrinho de compras, em que ter o mesmo item em mais de um carrinho de compras provavelmente n\u00e3o faz sentido em termos de dom\u00ednio). Isso pode ser aceit\u00e1vel ao usar o Couchbase como cache, mas n\u00e3o como armazenamento de dados prim\u00e1rio.<\/li>\n<li><strong>Tamanho das atualiza\u00e7\u00f5es<\/strong>: Durante um per\u00edodo de uso regular, um usu\u00e1rio individual pode publicar centenas ou milhares de atualiza\u00e7\u00f5es. Isso pode resultar em um documento muito grande que pode tornar as opera\u00e7\u00f5es de E\/S mais lentas. Isso pode ser atenuado com a fun\u00e7\u00e3o <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/subdoc-explained\/\">API de subdocumento<\/a>mas observe tamb\u00e9m que o Couchbase tem um limite m\u00e1ximo de 20 MB por documento.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Observa\u00e7\u00e3o: H\u00e1 um problema de N+1 aqui tamb\u00e9m (amigos de amigos, etc.), mas n\u00e3o vou perder tempo abordando isso. \u00c9 um problema que n\u00e3o \u00e9 exclusivo de nenhum dos bancos de dados.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Al\u00e9m disso, pode n\u00e3o ser que, quando o aplicativo l\u00ea ou grava um usu\u00e1rio, ele precise ler ou gravar amigos e atualiza\u00e7\u00f5es. E, ao escrever uma atualiza\u00e7\u00e3o, \u00e9 pouco prov\u00e1vel que o aplicativo precise atualizar um usu\u00e1rio. Como essas entidades muitas vezes podem ser lidas\/gravadas por conta pr\u00f3pria, isso indica que elas precisam ser modeladas como documentos separados.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Observe a matriz no <code>Amigos<\/code> no documento do usu\u00e1rio e o valor no campo <code>Usu\u00e1rio<\/code> no documento de atualiza\u00e7\u00e3o. Esses valores podem ser usados para recuperar os documentos associados. Mais adiante neste post, discutirei como fazer isso com opera\u00e7\u00f5es de chave\/valor e como fazer isso com N1QL.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Em resumo, h\u00e1 duas maneiras de modelar dados em um banco de dados de documentos. O exemplo do carrinho de compras usou <strong>objetos aninhados<\/strong>enquanto o exemplo de m\u00eddia social usou <strong>documentos separados<\/strong>. Nesses exemplos, a escolha foi relativamente simples. Quando estiver tomando suas pr\u00f3prias decis\u00f5es de modelagem, aqui est\u00e1 uma folha de dicas \u00fatil:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Tabela 2. Folha de consulta de dados de modelagem<\/caption>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">Se ...<\/th>\n<th class=\"tableblock halign-left valign-top\">Ent\u00e3o, considere...<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">O relacionamento \u00e9 de 1 para 1 ou de 1 para muitos<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos aninhados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">O relacionamento \u00e9 de muitos para 1 ou de muitos para muitos<\/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\">As leituras de dados s\u00e3o, em sua maioria, campos pai<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Documento separado<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">As leituras de dados s\u00e3o, em sua maioria, campos pai + filho<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos aninhados<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">As leituras de dados s\u00e3o, em sua maioria, parentais <em>ou<\/em> filho (n\u00e3o 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\">As grava\u00e7\u00f5es de dados s\u00e3o, em sua maioria, pai <em>e<\/em> crian\u00e7a (ambos)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Objetos aninhados<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"sect2\">\n<h3 id=\"_key_value_operations\">Opera\u00e7\u00f5es de chave\/valor<\/h3>\n<div class=\"paragraph\">\n<p>Para obter documento(s) no Couchbase, a maneira mais simples e r\u00e1pida \u00e9 solicit\u00e1-los por chave. Quando voc\u00ea tiver uma das chaves <code>Usu\u00e1rio do Friendbook<\/code> documentos acima, voc\u00ea pode executar outra opera\u00e7\u00e3o para obter os documentos associados. Por exemplo, eu poderia pedir ao Couchbase que me fornecesse os documentos das chaves 2, 3 e 1031 (como uma opera\u00e7\u00e3o em lote). Isso me forneceria os documentos de cada amigo. Em seguida, posso repetir isso para <code>Atualiza\u00e7\u00f5es<\/code>e assim por diante.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A vantagem disso \u00e9 a velocidade: as opera\u00e7\u00f5es de chave\/valor s\u00e3o muito r\u00e1pidas no Couchbase, e voc\u00ea provavelmente obter\u00e1 valores diretamente da RAM.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>A desvantagem \u00e9 que isso envolve pelo menos duas opera\u00e7\u00f5es (obter o documento FriendbookUser e, em seguida, obter as atualiza\u00e7\u00f5es). Portanto, isso pode envolver alguma codifica\u00e7\u00e3o extra. Tamb\u00e9m pode exigir que voc\u00ea pense com mais cuidado sobre como construir chaves de documentos (mais sobre isso adiante).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_n1ql\">N1QL<\/h3>\n<div class=\"paragraph\">\n<p>No Couchbase, voc\u00ea pode escrever consultas usando N1QL, que \u00e9 SQL para JSON. Isso inclui o <code>JUNTAR<\/code> palavra-chave. Isso me permite, por exemplo, escrever uma consulta para obter as 10 atualiza\u00e7\u00f5es mais recentes e os usu\u00e1rios que correspondem a elas.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">Lista p\u00fablica GetTenLatestUpdates()\r\n{\r\n    var n1ql = @\"SELECT up.body, up.postedDate, { 'id': META(u).id, u.name} AS `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 result.Rows;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>O resultado dessa consulta seria:<\/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>O N1QL permite que voc\u00ea tenha grande flexibilidade na recupera\u00e7\u00e3o de dados. N\u00e3o preciso ficar restrito apenas ao uso de chaves. Tamb\u00e9m \u00e9 f\u00e1cil de aprender, pois \u00e9 um superconjunto de SQL com o qual os usu\u00e1rios do SQL Server se sentir\u00e3o confort\u00e1veis rapidamente. Entretanto, a desvantagem aqui \u00e9 que a indexa\u00e7\u00e3o \u00e9 importante. Ainda mais do que a indexa\u00e7\u00e3o do SQL Server. Se voc\u00ea fosse escrever uma consulta no banco de dados <code>Nome<\/code> por exemplo, voc\u00ea deve ter um \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` (Name) USING GSI;<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Caso contr\u00e1rio, a consulta n\u00e3o ser\u00e1 executada (se voc\u00ea n\u00e3o tiver indexa\u00e7\u00e3o) ou n\u00e3o ter\u00e1 desempenho (se voc\u00ea tiver criado apenas um \u00edndice prim\u00e1rio).<\/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\">H\u00e1 pr\u00f3s e contras na decis\u00e3o de usar ou n\u00e3o as refer\u00eancias<\/a>. Os valores em <code>amigos<\/code> e <code>usu\u00e1rio<\/code> s\u00e3o semelhantes \u00e0s chaves estrangeiras, pois fazem refer\u00eancia a outro documento. Mas n\u00e3o h\u00e1 imposi\u00e7\u00e3o de valores pelo Couchbase. O gerenciamento dessas chaves deve ser feito adequadamente pelo aplicativo. Al\u00e9m disso, embora o Couchbase forne\u00e7a transa\u00e7\u00f5es ACID para opera\u00e7\u00f5es com um \u00fanico documento, n\u00e3o h\u00e1 nenhuma transa\u00e7\u00e3o ACID para v\u00e1rios documentos dispon\u00edvel.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>H\u00e1 maneiras de lidar com essas ressalvas em sua camada de aplicativo que ser\u00e3o discutidas em postagens posteriores do blog nesta s\u00e9rie, portanto, fique atento!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_key_design_and_document_differentiation\">Principais diferencia\u00e7\u00f5es de design e documentos<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Em bancos de dados relacionais, as linhas de dados (normalmente, nem sempre) correspondem a uma chave prim\u00e1ria, que geralmente \u00e9 um n\u00famero inteiro ou um Guid e, \u00e0s vezes, uma chave composta. Essas chaves n\u00e3o t\u00eam necessariamente nenhum significado: elas s\u00e3o usadas apenas para identificar uma linha em uma tabela. Por exemplo, duas linhas de dados em duas tabelas diferentes podem ter a mesma chave (um valor inteiro de 123, por exemplo), mas isso n\u00e3o significa necessariamente que os dados estejam relacionados. Isso ocorre porque o esquema imposto pelos bancos de dados relacionais geralmente transmite significado por si s\u00f3 (por exemplo, um nome de tabela).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Em bancos de dados de documentos como o Couchbase, n\u00e3o h\u00e1 nada equivalente a uma tabela, por si s\u00f3. Cada documento em um bucket deve ter uma chave exclusiva. Mas um bucket pode ter uma variedade de documentos. Portanto, muitas vezes \u00e9 aconselh\u00e1vel criar uma maneira de diferenciar os documentos em um bucket.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_meaningful_keys\">Chaves significativas<\/h3>\n<div class=\"paragraph\">\n<p>Por exemplo, \u00e9 perfeitamente poss\u00edvel ter um <code>Usu\u00e1rio do Friendbook<\/code> com uma chave de <code>123<\/code>e um <code>Atualiza\u00e7\u00e3o<\/code> com uma chave de <code>456<\/code>. No entanto, talvez seja aconselh\u00e1vel adicionar mais algumas informa\u00e7\u00f5es sem\u00e2nticas \u00e0 chave. Em vez de <code>123<\/code>use uma chave de <code>FriendbookUser::123<\/code>. Os benef\u00edcios de colocar informa\u00e7\u00f5es sem\u00e2nticas em sua chave incluem:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Legibilidade<\/strong>: Em uma r\u00e1pida olhada, voc\u00ea pode saber para que serve um documento.<\/li>\n<li><strong>Capacidade de refer\u00eancia<\/strong>: Se voc\u00ea tiver um <code>FriendbookUser::123<\/code> ent\u00e3o voc\u00ea poderia ter outro documento com uma chave <code>FriendbookUser::123::Atualiza\u00e7\u00f5es<\/code> que tem uma associa\u00e7\u00e3o impl\u00edcita.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>Se voc\u00ea planeja usar N1QL, talvez n\u00e3o precise que as chaves sejam t\u00e3o significativas do ponto de vista sem\u00e2ntico. Em termos de desempenho, quanto mais curta for a chave, mais delas poder\u00e3o ser armazenadas na RAM. Portanto, s\u00f3 use esse padr\u00e3o se estiver planejando fazer uso intenso de opera\u00e7\u00f5es de chave\/valor em vez de consultas N1QL.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_discriminator_fields\">Campos de discrimina\u00e7\u00e3o<\/h3>\n<div class=\"paragraph\">\n<p>Ao usar o N1QL, outra t\u00e1tica que pode ser usada al\u00e9m ou em vez de chaves significativas \u00e9 adicionar campo(s) a um documento que seja(m) usado(s) para diferenciar o documento. Isso geralmente \u00e9 implementado como um <code>tipo<\/code> em um documento.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">{\r\n    \"address\" : \"1800 Brown Rd\",\r\n    \"city\" : \"Groveport\",\r\n    \"state\" : \"OH\",\r\n    \"type\" : \"address\"\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>N\u00e3o h\u00e1 nada de m\u00e1gico no <code>tipo<\/code> campo. N\u00e3o \u00e9 uma palavra reservada em um documento e n\u00e3o \u00e9 tratada de forma especial pelo Couchbase Server. Ele poderia facilmente ser chamado de <code>documentType<\/code>, <code>theType<\/code>etc. Mas ele pode ser \u00fatil em seu aplicativo ao usar o N1QL para consultar documentos de um 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 = 'address'<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Voc\u00ea pode at\u00e9 dar um passo adiante e adicionar um objeto incorporado aos seus documentos para atuar como uma esp\u00e9cie de \"metadados\" falsos:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">{\r\n    \"address\" : \"1800 Brown Rd\",\r\n    \"city\" : \"Groveport\",\r\n    \"state\" : \"OH\",\r\n    \"documentInfo\" : {\r\n        \"type\" : \"address\",\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>Isso pode ser um exagero para alguns aplicativos. \u00c9 semelhante a um padr\u00e3o que vi em bancos de dados relacionais: uma tabela \"raiz\" para simular a heran\u00e7a em um banco de dados relacional, ou talvez os mesmos campos anexados a todas as tabelas.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion_of_part_1\">Conclus\u00e3o da parte 1<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Esta postagem do blog abordou a modelagem de dados usando desnormaliza\u00e7\u00e3o, modelagem de dados usando refer\u00eancias, design de chaves e campos discriminados. A modelagem de dados em um banco de dados de documentos \u00e9 um processo de pensamento, uma esp\u00e9cie de forma de arte, e n\u00e3o um processo mec\u00e2nico. N\u00e3o h\u00e1 uma receita de como modelar seus dados em um banco de dados de documentos: isso depende muito de como seu aplicativo interage com os dados.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Voc\u00ea pode obter o <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">c\u00f3digo-fonte de toda a s\u00e9rie do blog no GitHub agora<\/a>que foi apresentado nesta postagem do blog. Se voc\u00ea tiver d\u00favidas sobre v\u00e1rias partes desse c\u00f3digo, fique \u00e0 vontade para deixar um coment\u00e1rio abaixo ou abrir um problema no GitHub.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Fique atento ao pr\u00f3ximo blog da s\u00e9rie, no qual ser\u00e3o discutidos dados e migra\u00e7\u00e3o de dados.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Se voc\u00ea tiver alguma d\u00favida, deixe um coment\u00e1rio abaixo, <a href=\"https:\/\/twitter.com\/mgroves\">entre em contato comigo no Twitter<\/a>ou use o <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/forums\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">F\u00f3runs do 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 v26.1 (Yoast SEO v26.1.1) - 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\/pt\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\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\/pt\/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\":\"pt-BR\",\"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\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\",\"@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\/pt\/author\/matthew-groves\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Data Modeling in SQL Server: Making the Move to Couchbase","description":"Esta postagem explica como mover um banco de dados de documentos quando voc\u00ea tem um hist\u00f3rico relacional. Especificamente, o Microsoft SQL Server em compara\u00e7\u00e3o com o 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\/pt\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","og_locale":"pt_BR","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\/pt\/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":"pt-BR","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":"Esta postagem explica como mover um banco de dados de documentos quando voc\u00ea tem um hist\u00f3rico relacional. Especificamente, o Microsoft SQL Server em compara\u00e7\u00e3o com o Couchbase Server.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@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":"Blog do Couchbase","description":"Couchbase, o banco de dados 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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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":"pt-BR","@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 \u00e9 um cara que adora programar. N\u00e3o importa se \u00e9 C#, jQuery ou PHP: ele enviar\u00e1 solicita\u00e7\u00f5es de pull para qualquer coisa. Ele tem programado profissionalmente desde que escreveu um aplicativo de ponto de venda QuickBASIC para a pizzaria de seus pais nos anos 90. Atualmente, ele trabalha como gerente s\u00eanior de marketing de produtos da Couchbase. Seu tempo livre \u00e9 passado com a fam\u00edlia, assistindo aos Reds e participando da comunidade de desenvolvedores. Ele \u00e9 autor de AOP in .NET, Pro Microservices in .NET, autor da Pluralsight e Microsoft MVP.","sameAs":["https:\/\/crosscuttingconcerns.com","https:\/\/x.com\/mgroves"],"url":"https:\/\/www.couchbase.com\/blog\/pt\/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","author_category":"","last_name":"Groves","first_name":"Matthew","job_title":"","user_url":"https:\/\/crosscuttingconcerns.com","description":"Matthew D. Groves \u00e9 um cara que adora programar.  N\u00e3o importa se \u00e9 C#, jQuery ou PHP: ele enviar\u00e1 solicita\u00e7\u00f5es de pull para qualquer coisa.  Ele tem programado profissionalmente desde que escreveu um aplicativo de ponto de venda QuickBASIC para a pizzaria de seus pais nos anos 90.  Atualmente, ele trabalha como gerente s\u00eanior de marketing de produtos da Couchbase. Seu tempo livre \u00e9 passado com a fam\u00edlia, assistindo aos Reds e participando da comunidade de desenvolvedores.  Ele \u00e9 autor de AOP in .NET, Pro Microservices in .NET, autor da Pluralsight e Microsoft MVP."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=2521"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2521\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/2574"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=2521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=2521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=2521"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=2521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}