{"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\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","title":{"rendered":"Moving from SQL Server to Couchbase Part 1: Data Modeling"},"content":{"rendered":"<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<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 <a href=\"https:\/\/www.couchbase.com\/developers\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Server<\/a>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In three parts, I\u2019m going to cover:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Data modeling (this blog post)<\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/sql-server-couchbase-data-migration\/\">The data itself<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/moving-sql-server-couchbase-app-migration\/\">Applications using the data<\/a><\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>The goal is to lay down some general guidelines that you can apply to your application planning and design.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>If you would like to follow along, I\u2019ve created an application that demonstrates Couchbase and SQL Server side-by-side. <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">Get the source code from GitHub<\/a>, and make sure to <a href=\"https:\/\/couchbase.com\/downloads\/\">download a developer preview of Couchbase Server<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_why_would_i_do_this\">Why would I do this?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Before we get started, I want to spend a little bit of time on motivation. There are 3 main reasons why one might consider using a document data store instead of (or in addition to) a relational database. Your motivation may be one or all three:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Speed<\/strong>: Couchbase Server uses a <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\">memory-first architecture<\/a> which can provide a great speed boost as compared to a relational databases<\/li>\n<li><strong>Scalability<\/strong>: Couchbase Server is a <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/architecture\/architecture-intro.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">distributed database<\/a>, which allows you to scale out (and scale back in) capacity by just racking up commodity hardware. Built-in Couchbase features like auto-sharding, replication, load balancing make scaling a lot smoother and easier than relational databases.<\/li>\n<li><strong>Flexibility<\/strong>: Some data fits nicely in a relational model, but some data can benefit from the <a href=\"https:\/\/docs.couchbase.com\/server\/6.0\/learn\/data\/document-data-model.html\">flexibility of using JSON<\/a>. Unlike SQL Server, schema maintenance is no longer an issue. With JSON: the schema bends as you need it to.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>For these reasons and others, <a href=\"https:\/\/www.couchbase.com\/sql-server\/\">Gannett switched from SQL Server to Couchbase Server<\/a>. If you are considering this, definitely <a href=\"https:\/\/www.couchbase.com\/nosql-resources\/presentations\/how-gannett-achieved-scalability-and-agility-with-nosql.html\">check out Gannett\u2019s full presentation<\/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>It should be noted that document databases and relational databases can be complimentary. Your application may be best served by one, the other, or a combination of both. In many cases, it simply is not possible to completely remove relational databases from your design, but a document database like Couchbase Server can still bring the above benefits to your software. The rest of this blog series will assume you have a SQL Server background and are either replacing, supplimenting, or starting a new greenfield project using Couchbase.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The ease or difficulty of transitioning an existing application varies widely based on a number of factors. In some cases it may be extremely easy; in some cases it will be time-consuming and difficult; in some (shrinking number of) cases it may not even be a good idea.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_understanding_the_differences\">Understanding the differences<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The first step is to understand how data is modeled in a document database. In a relational database, data is typically stored flat in a table and it is given structure with primary and foreign keys. As a simple example, let\u2019s consider a relational database for a web site that has a shopping cart as well as social media features. (In this example, those features are unrelated to keep things simple).<\/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>In a document database, data is stored as keys and values. A Couchbase bucket contains documents; each document has a unique key and a JSON value. There are no foreign keys (or, more accurately, there are no foreign key constraints).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Here\u2019s a high-level comparison of SQL Server features\/naming as compared to Couchbase:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Table 1. SQL Server compared to 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\">Couchbase Server<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Server<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Cluster<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Database<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Bucket<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Row(s) from table(s)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Document<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Column<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">JSON key\/value<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Primary Key<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Document Key<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>These comparisons are a metaphorical starting point. Looking at that table, it might be tempting to take a simplistic approach. &#8220;I have 5 tables, therefore I\u2019ll just create 5 different types of documents, with one document per row.&#8221; This is the equivalent of literally translating a written language. The approach may work sometimes, but it doesn\u2019t take into account the full power of a document database that uses JSON. Just as a literal translation of a written language doesn\u2019t take into account cultural context, idioms, and historical context.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Because of the flexibility of JSON, the data in a document database can be structured more like a domain object in your application. Therefore you don\u2019t have an impedence mismatch that is often addressed by OR\/M tools like Entity Framework and NHibernate.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>There are two main approaches you can use when modeling data in Couchbase that we will examine further:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Denormalization<\/strong> &#8211; Instead of splitting data between tables using foreign keys, group concepts together into a single document.<\/li>\n<li><strong>Referential<\/strong> &#8211; Concepts are given their own documents, but reference other documents using the document key.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_denormalization_example\">Denormalization example<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Let\u2019s consider the &#8220;shopping cart&#8221; entity.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>To represent this in a relational database would likely require two tables: a ShoppingCart table and a ShoppingCartItem table with a foreign key to a row in ShoppingCart.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>When creating the model for a document database, the decision has to be made whether to continue modeling this as two separate entities (e.g. a Shopping Cart document and corresponding Shopping Cart Item documents) or whether to &#8220;denormalize&#8221; and combine a row from ShoppingCart and row(s) from ShoppingCartItem into a single document to represent a shopping cart.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In Couchbase, using a denormalization strategy, a shopping cart and the items in it would be represented by a single document.<\/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\": 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>Notice that the relationship between the items and the shopping cart is now implicit to being contained in the same document. No more need for an ID on the items to represent a relationship.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In C#, you would likely define <code>ShoppingCart<\/code> and <code>Item<\/code> classes to model this data:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public class 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; }    \/\/ necessary for SQL Server, not for 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>These classes would still make sense with Couchbase, so you can reuse them or design them this way. But with a relational database, this design does not match up in a direct way.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Hence the need for OR\/Ms like NHibernate or Entity Framework. The way the above model can be mapped to a relational database is represented in Entity Framework* like this:<\/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);\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.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>*Other OR\/Ms will have similar mappings<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Based on these mappings and an analysis of the use cases, I could decide that it would be modeled as a single document in Couchbase. <code>ShoppingCartItemMap<\/code> only exists so that the OR\/M knows how to populate the <code>Items<\/code> property in <code>ShoppingCart<\/code>. Also, it\u2019s unlikely that the application will be doing reads of the shopping cart without <em>also<\/em> needing to read the items.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In a later post, OR\/Ms will be discussed further, but for now I can say that the <code>ShoppingCartMap<\/code> and <code>ShoppingCartItemMap<\/code> classes are not necessary when using Couchbase, and the <code>Id<\/code> field from <code>Item<\/code> isn\u2019t necessary. In fact, the Couchbase .NET SDK can directly populate a <code>ShoppingCart<\/code> object without an OR\/M in a single line of code:<\/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>This isn\u2019t to say that using Couchbase will always result in shorter, easier to read code. But for certain use cases, it can definitely have an impact.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_referential_example\">Referential example<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>It\u2019s not always possible or optimal to denormalize relationships like the <code>ShoppingCart<\/code> example. In many cases, a document will need to reference another document. Depending on how your application expects to do reads and writes, you may want to keep your model in separate documents by using referencing.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Let\u2019s look at an example where referencing might be the best approach. Suppose your application has some social media elements. Users can have friends, and users can post text updates.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>One way to model this:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>Users as individual documents<\/li>\n<li>Updates as individual documents that reference a user<\/li>\n<li>Friends as an array of keys within a user document<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>With two users, two updates, we would have 4 documents in Couchbase that look like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-JavaScript\">[\r\n  \/\/ Key: \"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\"\r\n  },\r\n\r\n  \/\/ Key: \"c5f05561-9fbf-4ab0-b68f-e392267c0703\"\r\n  {\r\n    \"friends\": [ ],\r\n    \"name\": \"Nic Raboy\",\r\n    \"type\": \"User\"\r\n  },\r\n\r\n  \/\/ Key: \"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  \/\/ Key: \"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>I decided to model &#8216;friends&#8217; as a one-way relationship (like Twitter) for this example, which is why Matt Groves has Nic Raboy as a friend but not vice-versa. (Don\u2019t read too much into this, Nic :).<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The way to model this in C# could be:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public class 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>The <code>Update<\/code> to <code>FriendbookUser<\/code> relationship can be modeled as either a <code>Guid<\/code> or as another <code>FriendbookUser<\/code> object. This is an implementation detail. You might prefer one, the other, or both, depending on your application needs and\/or how your OR\/M works. In either case, the underlying model is the same.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Here\u2019s the mapping I used for these classes in Entity Framework. Your mileage may vary, depending on how you use EF or other OR\/M tools. Focus on the underlying model and not the details of the OR\/M mapping tool.<\/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>If, instead of storing these entities as separate documents, we applied the same denormalization as the shopping cart example and attempted to store a user and updates in one document, we would end up with some problems.<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Duplication of friends<\/strong>: each user would store the details for their friends. This is not tenable, because now a user\u2019s information would be stored in multiple places instead of having a single source of truth (unlike the shopping cart, where having the same item in more than one shopping cart probably doesn\u2019t make any domain sense). This might be okay when using Couchbase as a cache, but not as a primary data store.<\/li>\n<li><strong>Size of updates<\/strong>: Over a period of regular use, an individual user could post hundreds or thousands of updates. This could lead to a very large document which could slow down I\/O operations. This can be mitigated with Couchbase\u2019s <a href=\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\">sub-document API<\/a>, but also note that Couchbase has a ceiling of 20mb per document.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Note: There\u2019s an N+1 problem here too (friends of friends, etc), but I\u2019m not going to spend time on addressing that. It\u2019s a problem that\u2019s not unique to either database.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Additionally, it may not be the case that when the application reads or writes a user that it will need to read or write friends &amp; updates. And, when writing an update, it\u2019s not likely that the application will need to update a user. Since these entities may often be read\/written on their own, that indicates that they need to be modeled as separate documents.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Note the array in the <code>Friends<\/code> field in the user document and the value in the <code>User<\/code> field in the update document. These values can be used to retrieve the associated documents. Later in this post, I\u2019ll discuss how to do it with key\/value operations and how to do it with N1QL.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>To sum up, there are two ways to model data in a document database. The shopping cart example used <strong>nested objects<\/strong>, while the social media example used <strong>separate documents<\/strong>. In those examples, it was relatively straightforward to choose. When you\u2019re making your own modeling decisions, here\u2019s a handy cheat sheet:<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<caption class=\"title\">Table 2. Modeling Data Cheat Sheet<\/caption>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">If \u2026\u200b<\/th>\n<th class=\"tableblock halign-left valign-top\">Then consider\u2026\u200b<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Relationship is 1-to-1 or 1-to-many<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Nested objects<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Relationship is many-to-1 or many-to-many<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Separate documents<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Data reads are mostly parent fields<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Separate document<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Data reads are mostly parent + child fields<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Nested objects<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Data reads are mostly parent <em>or<\/em> child (not both)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Separate documents<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Data writes are mostly parent <em>and<\/em> child (both)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Nested objects<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"sect2\">\n<h3 id=\"_key_value_operations\">Key\/value operations<\/h3>\n<div class=\"paragraph\">\n<p>To get document(s) in Couchbase, the simplest and fastest way is to ask for them by key. Once you have one of the <code>FriendbookUser<\/code> documents above, you can then execute another operation to get the associated documents. For instance, I could ask Couchbase to give me the documents for keys 2, 3, and 1031 (as a batch operation). This would give me the documents for each friend. I can then repeat that for <code>Updates<\/code>, and so on.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The benefit to this is speed: key\/value operations are very fast in Couchbase, and you will likely be getting values directly from RAM.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The drawback is that it involves at least two operations (get FriendbookUser document, then get the Updates). So this may involve some extra coding. It may also require you to think more carefully about how you construct document keys (more on that later).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_n1ql\">N1QL<\/h3>\n<div class=\"paragraph\">\n<p>In Couchbase, you have the ability to write queries using N1QL, which is SQL for JSON. This includes the <code>JOIN<\/code> keyword. This allows me to, for instance, write a query to get the 10 latest updates and the users that correspond to them.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight decode:true\"><code class=\"language-C#\">public List 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>The result of this query would be:<\/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 allows you to have great flexibility in retrieving data. I don\u2019t have to be restricted by just using keys. It\u2019s also easy to pick up, since it\u2019s a superset of SQL that SQL Server users will be comfortable with quickly. However, the tradeoff here is that indexing is important. Even more so than SQL Server indexing. If you were to write a query on the <code>Name<\/code> field, for instance, you should have an index like:<\/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>Otherwise the query will fail to execute (if you have no indexing) or it will not be performant (if you only have a primary index created).<\/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\">There are pros and cons in deciding to use referencing or not<\/a>. The values in <code>friends<\/code> and <code>user<\/code> are similar to foreign keys, in that they reference another document. But there is no enforcement of values by Couchbase. The management of these keys must be handled properly by the application. Further, while Couchbase provides ACID transactions for single document operations, there is no multi-document ACID transaction available.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>There are ways to deal with these caveats in your application layer that will be discussed further in later blog posts in this series, so stay tuned!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_key_design_and_document_differentiation\">Key design and document differentiation<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>In relational databases, rows of data (typically, not always) correspond to a primary key, which is often an integer or a Guid, and sometimes a composite key. These keys don\u2019t necessarily have any meaning: they are just used to identify a row within a table. For instance, two rows of data in two different tables may have the same key (an integer value of 123, for instance), but that doesn\u2019t necessarily mean the data is related. This is because the schema enforced by relational databases often conveys meaning on its own (e.g. a table name).<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In document databases like Couchbase, there isn\u2019t anything equivalent to a table, per se. Each document in a bucket must have a unique key. But a bucket can have a variety of documents in it. Therefore, it\u2019s often wise to come up with a way to differentiate documents within a bucket.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_meaningful_keys\">Meaningful keys<\/h3>\n<div class=\"paragraph\">\n<p>For instance, it\u2019s entirely possible to have a <code>FriendbookUser<\/code> document with a key of <code>123<\/code>, and an <code>Update<\/code> document with a key of <code>456<\/code>. However, it might be wise to add some more semantic information to the key. Instead of <code>123<\/code>, use a key of <code>FriendbookUser::123<\/code>. The benefits to putting semantic information in your key include:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li><strong>Readability<\/strong>: At a glance, you can tell what a document is for.<\/li>\n<li><strong>Referenceability<\/strong>: If you have a <code>FriendbookUser::123<\/code> document, then you could have another document with a key <code>FriendbookUser::123::Updates<\/code> that has an implicit association.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>If you plan on using N1QL, then you may not need keys to be this semantically meaningful. In terms of performance, the shorter the key is, the more of them can be stored in RAM. So only use this pattern if you plan on making heavy use of key\/value operations instead of N1QL queries.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_discriminator_fields\">Discriminator fields<\/h3>\n<div class=\"paragraph\">\n<p>When using N1QL, another tactic that can be used in addition to or instead of meaningful keys is to add field(s) to a document that are used to differentiate the document. This is often implemented as a <code>type<\/code> field within a document.<\/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>There\u2019s nothing magical about the <code>type<\/code> field. It\u2019s not a reserved word within a document and it\u2019s not treated specially by Couchbase Server. It could just as easily be named <code>documentType<\/code>, <code>theType<\/code>, etc. But it can be useful within your application when using N1QL to query documents of a certain kind.<\/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>You may even take it a step further and add an embedded object to your documents to act as a kind of faux &#8216;meta data&#8217;:<\/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>That may be overkill for some applications. It\u2019s similar to a pattern I\u2019ve seen in relational databases: a &#8216;root&#8217; table to simulate inheritence within a relational database, or perhaps the same fields tacked on to every table.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion_of_part_1\">Conclusion of part 1<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>This blog post covered data modeling using denormalization, data modeling using referencing, key design, and discriminating fields. Modeling data in a document database is a thought process, something of an art form, and not a mechanical process. There is no prescription on how to model your data in a document database: it depends greatly on how your application interacts with your data.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>You can get the <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/045MigrateFromSQLServer\/src\/SQLServerToCouchbase\">source code for the entire blog series on GitHub now<\/a>, parts of which were featured in this blog post. If you have questions about various parts of that code, feel free to leave a comment below, or open an issue on GitHub.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Stay tuned for the next blog in the series, where data and data migration will be discussed.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>If you have any questions, please leave a comment below, <a href=\"https:\/\/twitter.com\/mgroves\">contact me on Twitter<\/a>, or use the <a href=\"https:\/\/www.couchbase.com\/forums\/?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Forums<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n","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>\n","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.8 (Yoast SEO v25.8) - 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\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\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\/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 minutes\" \/>\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\":\"en-US\",\"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\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@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\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@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\":\"en-US\",\"@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\/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\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/","og_locale":"en_US","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\/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 minutes"},"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":"en-US","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":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/moving-from-sql-server-to-couchbase-part-1-data-modeling\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@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":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@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":"en-US","@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\/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 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."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2521","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=2521"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2521\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/2574"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=2521"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2521"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2521"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2521"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}