{"id":2327,"date":"2016-07-12T13:18:54","date_gmt":"2016-07-12T13:18:53","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2327"},"modified":"2025-10-09T07:25:56","modified_gmt":"2025-10-09T14:25:56","slug":"sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/","title":{"rendered":"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)"},"content":{"rendered":"<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p><em>This blog post is based on an <a href=\"https:\/\/www.couchbase.com\/blog\/developer-preview-of-new-sub-document-api-included-w-2.2.6-release-of-couchbase-.net-sdk\/\">earlier blog post by Jeff Morris<\/a> that covered the sub-document API while it was still in developer preview. There have been some changes to the API since that release.<\/em><\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>With <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/introduction\/intro.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Server 4.5<\/a> and the <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.5\/sdk\/dotnet\/start-using-sdk.html?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">.NET SDK 2.3.x<\/a>, you can now use the <em>Sub-document<\/em> feature in your .NET application.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In previous Couchbase releases, all document mutations were atomic and involve the entire document. If you only want to change a single field and then do an update, the entire document in Couchbase server is copied over by the new revision. The problem with is that if the document is large or the network slow (or both), then a lot of resources are wasted sending data that hasn\u2019t been modified. A better, more performant solution would be to just send the portion of the document or the value which has been mutated. Essentially, that is what you get with sub-document API; when you update an element or delete an element of a document, only the path of the fragment to be mutated is sent over the wire and only that part of the document is modified.<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\"><img decoding=\"async\" src=\"\/wp-content\/original-assets\/2016\/july\/sub-document-api-in-couchbase-server-4.5-with-the-.net-sdk-revisted\/subdocument_001.jpg\" alt=\"Subdocument\" \/><\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>There are several different operations that are supported by the API, from mutations on individual nested elements (aka <em>sub-<\/em>documents) to array and dictionary modifications. Counter operations are also supported, as are retrieval operations for embedded JSON fragments.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The API is exposed via a <em>fluent<\/em> interface which allows you to append multiple operations and then execute them against the document atomically. There are two different &#8220;builders&#8221;: a builder for mutation operations and a builder for reads or &#8220;lookups&#8221; (which can also check if an element exists at a given path).<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueprerequisite-couchbase-server-4-5\">Prerequisite: Couchbase Server 4.5<\/h3>\n<div class=\"paragraph\">\n<p>In order to follow the examples below, you\u2019ll need to download and install <a href=\"https:\/\/www.couchbase.com\/get-started-developing-nosql#Download_Couchbase_Server?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Couchbase Server 4.5<\/a>. If you\u2019ve never installed Couchbase Server before, you can check out my video on <a href=\"https:\/\/www.couchbase.com\/blog\/how-to-install-couchbase-server-on-windows-video\/\">how to install Couchbase Server on Windows<\/a>. It\u2019s really easy, no matter what OS you are using.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"truesub-document-api-overview\">Sub-Document API Overview<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The following examples will use a document with an id of &#8220;puppy&#8221; and will start out looking like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">  {\r\n  \"type\": \"dog\",\r\n  \"breed\": \"Pitbull\/Chihuahua\",\r\n  \"name\": \"Puppy\",\r\n  \"toys\": [\r\n    \"squeaker\",\r\n    \"ball\",\r\n    \"shoe\"\r\n  ],\r\n  \"owner\": {\r\n    \"type\": \"servant\",\r\n    \"name\": \"Don Knotts\",\r\n    \"age\": 63\r\n  },\r\n  \"attributes\": {\r\n    \"fleas\": true,\r\n    \"color\": \"white\",\r\n    \"eyeColor\": \"brown\",\r\n    \"age\": 5,\r\n    \"dirty\": true,\r\n    \"sex\": \"female\"\r\n  }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>All of the <a href=\"https:\/\/github.com\/couchbaselabs\/blog-source-code\/tree\/master\/Groves\/011SubDocumentInDotNet\/src\">examples are available on Github<\/a> so you can clone the project and play around with the API.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truemutateinbuilder-and-lookupinbuilder\">MutateInBuilder and LookupInBuilder<\/h3>\n<div class=\"paragraph\">\n<p>The Sub-document API offers two new Types that utilize a builder pattern via a fluent-interface for chaining together multiple operations on a document. Both objects are created by calling <code>MutateIn<\/code> or <code>LookupIn<\/code> on a <code>CouchbaseBucket<\/code> object and passing in the key of the document you are working against:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">\/\/Initialize the cluster helper with the default settings - i.e. localhost\r\nClusterHelper.Initialize();\r\nvar bucket = ClusterHelper.GetBucket(\"default\");\r\n\r\n\/\/create a mutation builder for the document \"thekey\"\r\nvar mutate = bucket.MutateIn(\"thekey\");\r\n\r\n\/\/create a lookup builder for the document \"thekey2\"\r\nvar lookup = bucket.LookupIn(\"thekey2\");\r\n\r\nClusterHelper.Close();<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Once you have the builder object, you can chain together a number of operations to execute against the document, for example:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">var builder = bucket.LookupIn(id).\r\n    Get(\"type\").\r\n    Get(\"name\").\r\n    Get(\"owner\").\r\n    Exists(\"notfound\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Then you can send all of the operations to the server in a single batch:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">var fragment = builder.Execute();<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>You can check the result of one operation, by using OpStatus and a path. In this example, I\u2019m using the path <code>\"type\"<\/code>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">if (fragment.OpStatus(\"type\") == ResponseStatus.Success)\r\n{\r\n    string format = \"Path='{0}' Value='{1}'\";\r\n    Console.WriteLine(format, \"type\", fragment.Content(\"type\"));\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>These are some of the methods and fields you\u2019ll find on the <code>IDocumentFragment<\/code> interface.<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all spread\">\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Name<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Description<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Content(\u2026\u200b)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Gets the content for a given path or index.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Exists(\u2026\u200b)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Returns true if there is a result for a given path or index.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Count()<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">The count of current operations maintained by the builder.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">OpStatus(\u2026\u200b)<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">The <code>ResponseStatus<\/code> of an operation at a given index or path.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Status<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">The <code>ResponseStatus<\/code> for the entire multi-operation.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">Success<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">True if the entire multi-operation succeeds.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>Besides these properties or methods, there are all of the other properties inherited from <code>OperationResult<\/code> (which is the standard response from a key\/value operation): Upsert, Remove, Replace, and so on.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueerror-handling\">Error Handling<\/h3>\n<div class=\"paragraph\">\n<p>When sending multiple <em>mutations<\/em>, if one of them fails, the entire multi-operation request fails. This allows transactional &#8220;all-or-nothing&#8221; semantics when performing mutations within a single document.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>When sending multiple <em>lookups<\/em>, some operations may succeed and some may fail, with the server attempting to return as many items as requested.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>If the operation(s) failed, then the`Status` property will contain a top-level error response such as <code>SubDocMultiPathFailure<\/code>. This is an indication that you should dig deeper into the operation\u2019s results to get the specific error. You can do this by iterating: calling the <code>OpStatus<\/code> method and passing either the index or the path:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">var builder = bucket.LookupIn(id).\r\n    Get(\"type\").\r\n    Get(\"somepaththatdoesntexist\").\r\n    Get(\"owner\");\r\n\r\nvar fragment = builder.Execute();\r\nConsole.WriteLine(\"Generic error: {0}{1}Specific Error: {2}\",\r\n    fragment.Status, Environment.NewLine, fragment.OpStatus(1));\r\n\r\nConsole.WriteLine(\"Generic error: {0}{1}Specific Error: {2}\",\r\n   fragment.Status, Environment.NewLine, fragment.OpStatus(\"somepaththatdoesntexist\"));<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>In this case, since the path \u201csomepaththatdoesntexist\u201d didn\u2019t exist within the document, the specific error returned was <code>SubDocPathNotFound<\/code>. There are many different combinations of errors depending upon the builder type and the condition for the error.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"truelookupinbuilder-examples\">LookupInBuilder Examples<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The <code>LookUpInBuilder<\/code> type supports two operations: fetching a value by path and checking for the existence of a value at a given path.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueget\">Get:<\/h3>\n<div class=\"paragraph\">\n<p>Let\u2019s lookup the <code>owner<\/code> fragment. If I pass in &#8220;owner&#8221; as the path parameter to this method\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void GetExample(IBucket bucket, string path, string id)\r\n{\r\n    var builder = bucket.LookupIn(id).\r\n        Get(path).\r\n        Execute();\r\n\r\n    var fragment = builder.Content(path);\r\n    Console.WriteLine(fragment);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u2026\u200bthe output to console would be:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">{\r\n    \"type\": \"servant\",\r\n    \"name\": \"Don Knotts\",\r\n    \"age\": 63\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueexist\">Exist:<\/h3>\n<div class=\"paragraph\">\n<p>We can also check to see if a path exists. If I pass in &#8220;owner&#8221; as the path to this method\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ExistsExample(IBucket bucket, string path, string id)\r\n{\r\n    var builder = bucket.LookupIn(id).\r\n        Exists(path).\r\n        Execute();\r\n\r\n    var found = builder.Content(path);\r\n    Console.WriteLine(found);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u2026\u200bthe output is <code>true<\/code>, because the path <code>owner<\/code> does indeed exist within the document.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"truemutateinbuilder\">MutateInBuilder<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The MutateInBuilder offers a number of methods supporting mutations on scalar values, dictionaries and arrays, along with support for atomic counter operations.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueinsert\">Insert:<\/h3>\n<div class=\"paragraph\">\n<p>Insert adds a value to a dictionary, optionally allowing for the containing element (the dictionary itself) to be added.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void InsertExample(IBucket bucket, string id, string path, string value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        Insert(path, value, true).  \/\/ false is the default\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>If I called the above method like so:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">InsertExample(bucket, id,\"attributes.hairLength\", \"short\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Then the document\u2019s attributes dictionary will now look like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n\"attributes\":\r\n{\r\n    \"fleas\": true,\r\n    \"color\": \"white\",\r\n    \"eyeColor\": \"brown\",\r\n    \"age\": 5,\r\n    \"dirty\": true,\r\n    \"sex\": \"female\",\r\n    \"hairLength\": \"short\"\r\n}\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Note that the <code>Insert<\/code> method has an optional boolean parameter called <code>createParents<\/code>. It is false by default. If it\u2019s true, then the sub-document API will create the necessary path for the field to exist. If it\u2019s false, the sub-document API will only create the field if the parents of the field already exist. In the above example, the <code>attributes<\/code> field already existed.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In this next example, I\u2019ll use a path with a parent field (<code>anewattribute<\/code>) that doesn\u2019t already exist.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">InsertExample(bucket, id, \"anewattribute.withakey\", \"somevalue\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>This will create the new attribute called <code>anewattribute<\/code> in the document and add a single key called <code>withakey<\/code> with a value of <code>somevalue<\/code>.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">...\r\n\"anewattribute\":\r\n{\r\n    \"withakey\": \"somevalue\"\r\n}\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Now, if we passed <code>false<\/code> for <code>createParents<\/code> and the parent attribute did not exist, then the multi-mutation would fail with a top-level response status of <code>SubDocMultiPathFailure<\/code> and the specific error would be <code>SubDocPathNotFound<\/code>.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueupsert\">Upsert<\/h3>\n<div class=\"paragraph\">\n<p>Upsert will add or replace an existing dictionary entry. The usage is exactly the same as <code>Insert<\/code> with the exception of the method name being <code>Upsert<\/code>.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"trueremove\">Remove<\/h3>\n<div class=\"paragraph\">\n<p><code>Remove<\/code> will remove an element at a given path.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void RemoveExample(IBucket bucket, string id, string path)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        Remove(path).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>When I call this method:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">RemoveExample(bucket, id, \"owner.name\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Here\u2019s how the document will look afterwards:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n\"owner\":\r\n{\r\n    \"type\": \"servant\",\r\n    \"age\": 63\r\n},\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truereplace\">Replace<\/h3>\n<div class=\"paragraph\">\n<p>Replace will swap the value of element at a given path, failing if the path does not exist:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ReplaceExample(IBucket bucket, string id, string path, object value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        Replace(path, value).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>After I call this method:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">ReplaceExample(bucket, id, \"owner\", new { CatLover=true, CatName=\"celia\"});<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>The document will now have a different value for &#8220;owner&#8221;:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n\"owner\":\r\n{\r\n    \"catLover\": true,\r\n    \"catName\": \"celia\"\r\n},\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truearrayappend\">ArrayAppend<\/h3>\n<div class=\"paragraph\">\n<p>ArrayAppend adds a value to the end of an array, optionally adding the parent element (the array element itself) if it doesn\u2019t exist.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ArrayAppendExample(IBucket bucket, string id, string path, object value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        ArrayAppend(path, value, false).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>After that method with the &#8220;toys&#8221; path\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">ArrayAppendExample(bucket, id, \"toys\", \"slipper\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u2026\u200bthe <code>toys<\/code> array in the document will then have the value &#8220;slipper&#8221; in the last ordinal:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n\"toys\":\r\n[\r\n    \"squeaker\",\r\n    \"ball\",\r\n    \"shoe\",\r\n    \"slipper\"\r\n],\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truearrayprepend\">ArrayPrepend<\/h3>\n<div class=\"paragraph\">\n<p>ArrayPrepend works the same way as ArrayAppend, except it adds a value to the <em>front<\/em> of an array.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ArrayAppendExample(IBucket bucket, string id, string path, object value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        ArrayAppend(path, value, false).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Calling that method with the &#8220;toys&#8221; path\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">ArrayAppendExample(bucket, id, \"toys\", \"slipper\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>The <code>toys<\/code> array now has the value &#8220;slipper&#8221; in it\u2019s <em>first<\/em> ordinal:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n\"toys\":\r\n[\r\n    \"slipper\",\r\n    \"squeaker\",\r\n    \"ball\",\r\n    \"shoe\"\r\n],\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truearrayinsert\">ArrayInsert<\/h3>\n<div class=\"paragraph\">\n<p>ArrayPrepend puts a value at the beginning, ArrayAppend puts it at the end. Just to round things out, you can use ArrayInsert to put a value somewhere in between (at a given index).<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ArrayInsertExample(IBucket bucket, string id, string path, object value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        ArrayInsert(path, value).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>And then calling that method with &#8220;toys[2]&#8221;\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">ArrayInsertExample(bucket, id, \"toys[2]\", \"slipper\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>The <code>toys<\/code> array now has the value &#8220;slipper&#8221; at it\u2019s 3rd ordinal (index 2):<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">\"toys\":\r\n[\r\n    \"squeaker\",\r\n    \"ball\",\r\n    \"slipper\",\r\n    \"shoe\"\r\n ],<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truearrayaddunique\">ArrayAddUnique<\/h3>\n<div class=\"paragraph\">\n<p>ArrayAddUnique will inserts a value into an array, but it will fail if that value already exists (i.e. the value must be unique within the array).<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void ArrayAddUniqueExample(IBucket bucket, string id, string path, object value)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        ArrayAddUnique(path, value).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>When I call that with &#8220;shoe&#8221;\u2026\u200b<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">ArrayAddUniqueExample(bucket, id, \"toys\", \"shoe\");<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u2026\u200bsince the value &#8220;shoe&#8221; already exists in the original document\u2019s <code>toys<\/code> array, this will fail with the status <code>SubDocPathExists<\/code>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p><em>Note that this method only allows for JSON primitives to be inserted: strings, numbers, and special values for true, false or null. There is no way to compare for uniqueness without descending into each JSON object and comparing elements item by item.<\/em><\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truecounter\">Counter<\/h3>\n<div class=\"paragraph\">\n<p>Adds the specified delta (change) to an existing value, creating the element if it doesn\u2019t exist. It will default both the value and delta to 0. If the delta is negative, the value of the element will be decremented by the given delta.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>I\u2019ll create a method that uses <code>Counter<\/code>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">public static void CounterExample(IBucket bucket, string id, string path, long delta)\r\n{\r\n    var fragment = bucket.MutateIn(id).\r\n        Counter(path, delta).\r\n        Execute();\r\n\r\n    var status = fragment.OpStatus(path);\r\n    Console.WriteLine(status);\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Then, I\u2019ll call the method twice using a positive 1 and a negative 1 as the &#8220;deltas&#8221;:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-C#\">CounterExample(bucket, id, \"likes\", 1);\r\nCounterExample(bucket, id, \"likes\", -1);<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>After the first call, since the element doesn\u2019t exist it will be created and then set to one (1). The document will now look like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n    ],\r\n    \"likes\": 1\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>The second call passes a negative one (-1), so then the counter for <code>likes<\/code> will be decremented to zero (0). The JSON document will now look like this:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlightjs highlight\"><code class=\"language-javascript\">...\r\n    ],\r\n    \"likes\": 0\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"trueconclusion\">Conclusion<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Since the developer preview blog post, the Couchbase .NET SDK has been updated to version 2.3.2 (as of the time of this blog post). You can check out the work that\u2019s been done in the <a href=\"https:\/\/issues.couchbase.com\/projects\/NCBC\/versions\/13438?utm_source=blogs&amp;utm_medium=link&amp;utm_campaign=blogs\">Release Notes of Version 2.3.2<\/a>.<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truehow-to-get-v2-3-x\">How to get v2.3.x<\/h3>\n<div class=\"ulist\">\n<ul>\n<li>Download the binaries <a href=\"https:\/\/s3.amazonaws.com\/packages.couchbase.com\/clients\/net\/2.3\/Couchbase-Net-Client-2.3.3.zip\">for .NET SDK 2.3.x\u00a0from our repository (2.3.3 is the latest release).<\/a><\/li>\n<li>You can find the <a href=\"https:\/\/www.nuget.org\/packages\/CouchbaseNetClient\/\">latest SDKs on NuGet<\/a>.<\/li>\n<li>The <a href=\"https:\/\/github.com\/couchbase\/couchbase-net-client\">source code is available on Github<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"truefinal-notes\">Final Notes<\/h3>\n<div class=\"paragraph\">\n<p>The sub-document API gives you the ability to be more granular in your interactions with documents. You can modify and retrieve just the portions that you need.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Leave a comment below, <a href=\"https:\/\/twitter.com\/mgroves\">talk to me on Twitter<\/a>, or email me (matthew.groves AT couchbase DOT com) if you have any questions or comments.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This blog post is based on an earlier blog post by Jeff Morris that covered the sub-document API while it was still in developer preview. There have been some changes to the API since that release. With Couchbase Server 4.5 [&hellip;]<\/p>\n","protected":false},"author":71,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,1816],"tags":[1586],"ppma_author":[8937],"class_list":["post-2327","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-couchbase-server","tag-subdocument"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Sub-document API in Couchbase Server 4.5 with the .NET SDK<\/title>\n<meta name=\"description\" content=\"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.\" \/>\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\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)\" \/>\n<meta property=\"og:description\" content=\"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-07-12T13:18:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-09T14:25:56+00:00\" \/>\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=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\"},\"author\":{\"name\":\"Matthew Groves\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58\"},\"headline\":\"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)\",\"datePublished\":\"2016-07-12T13:18:53+00:00\",\"dateModified\":\"2025-10-09T14:25:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\"},\"wordCount\":1568,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"subdocument\"],\"articleSection\":[\".NET\",\"Couchbase Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\",\"name\":\"Sub-document API in Couchbase Server 4.5 with the .NET SDK\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2016-07-12T13:18:53+00:00\",\"dateModified\":\"2025-10-09T14:25:56+00:00\",\"description\":\"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)\"}]},{\"@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":"Sub-document API in Couchbase Server 4.5 with the .NET SDK","description":"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.","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\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/","og_locale":"en_US","og_type":"article","og_title":"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)","og_description":"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.","og_url":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/","og_site_name":"The Couchbase Blog","article_published_time":"2016-07-12T13:18:53+00:00","article_modified_time":"2025-10-09T14:25:56+00:00","author":"Matthew Groves","twitter_card":"summary_large_image","twitter_creator":"@mgroves","twitter_misc":{"Written by":"Matthew Groves","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/"},"author":{"name":"Matthew Groves","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/3929663e372020321b0152dc4fa65a58"},"headline":"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)","datePublished":"2016-07-12T13:18:53+00:00","dateModified":"2025-10-09T14:25:56+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/"},"wordCount":1568,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["subdocument"],"articleSection":[".NET","Couchbase Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/","url":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/","name":"Sub-document API in Couchbase Server 4.5 with the .NET SDK","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2016-07-12T13:18:53+00:00","dateModified":"2025-10-09T14:25:56+00:00","description":"This blog focuses on the Sub-document feature in .Net application. It gives you the ability to be more granular in your interactions with documents.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/sub-document-api-in-couchbase-server-4-5-with-the-net-sdk-revisted\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Sub-document API in Couchbase Server 4.5 with the .NET SDK (revisited)"}]},{"@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\/2327","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=2327"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2327\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=2327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2327"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2327"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}