{"id":2174,"date":"2016-07-28T18:54:41","date_gmt":"2016-07-28T18:54:41","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2174"},"modified":"2022-11-04T16:06:32","modified_gmt":"2022-11-04T23:06:32","slug":"subdoc-explained","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/","title":{"rendered":"Using the Sub-Document API to get (only) what you want"},"content":{"rendered":"<p>In <a href=\"https:\/\/www.couchbase.com\/blog\/sub-documents-change-only-what-you-need-to\/\">Matthew&#8217;s blog<\/a> the Sub-Document (<em>subdoc<\/em>) API feature is introduced with a short overview: In summary, subdoc allows efficient access to parts of documents (<em>sub<\/em>-documents) without requiring the transfer of the entire document over the network.<\/p>\n<p>Throughout this blog, we&#8217;ll use a reference document. This document will then be accessed through various ways using the subdoc API. Note that for each subdocument operation, <code>doc_size - op_size<\/code> bytes of bandwidth are being saved, where <code>doc_size<\/code> is the length of the document, and <code>op_size<\/code> is the length of the path and sub-document value.<\/p>\n<p>The document below is 500 bytes. Performing a simple <code>get()<\/code> would consume 500 bytes (plus protocol overhead) on the server response. If you only care for the delivery address, you could issue a <code>lookup_in('customer123', SD.get('addresses.delivery'))<\/code> call. You would receive only about 120 bytes over the network, a savings of over 400 bytes, using a quarter of the bandwidth of the equivalent full-document (<em>fulldoc<\/em>) operation.<\/p>\n<pre><code class=\"language-javascript\">{\r\n  \"name\": \"Douglas Reynholm\",\r\n  \"email\": \"douglas@reynholmindustries.com\",\r\n  \"addresses\": {\r\n    \"billing\": {\r\n      \"line1\": \"123 Any Street\",\r\n      \"line2\": \"Anytown \",\r\n      \"country\": \"United Kingdom\"\r\n    },\r\n    \"delivery\": {\r\n      \"line1\": \"123 Any Street\",\r\n      \"line2\": \"Anytown \",\r\n      \"country\": \"United Kingdom\"\r\n    }\r\n  },\r\n  \"purchases\": {\r\n    \"complete\": [\r\n      339, 976, 442, 666\r\n    ],\r\n    \"abandoned\": [\r\n      157, 42, 999\r\n    ]\r\n  }\r\n}<\/code><\/pre>\n<p>I&#8217;ll be demonstrating examples using a <a href=\"https:\/\/github.com\/mnunberg\/couchbase-python-client\/tree\/subdoc\">development branch of the Python SDK<\/a> and <a href=\"https:\/\/www.couchbase.com\/nosql-databases\/downloads?gtmRefId=FixedCTA-Download\">Couchbase Server 4.5 Developer Preview<\/a>.<br \/>\n[<b>EDIT:\u00a0<\/b>An experimental version of the sub-document API is now available in the latest <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.0\/sdks\/python-2.0\/download-links.html\">Python SDK<\/a>, version 2.0.8, and the examples below have been updated to reflect the latest API]<\/p>\n<p>You can read about the other new features in Couchbase 4.5 in <a href=\"https:\/\/www.couchbase.com\/blog\/introducing-couchbase-server-4.5-developer-preview\/\">Don Pinto&#8217;s blog post<\/a><\/p>\n<h3 id=\"toc_0\">Subdoc operations<\/h3>\n<p>A subdoc operation is a single action for a single path in a document. This may be expressed as <code>GET('addresses.billing')<\/code> or <code>ARRAY_APPEND('purchases.abandoned', 42)<\/code>. Some operations are <em>lookups<\/em> (they simply return data without modifying the document) while some are <em>mutations<\/em> (they modify the contents of the document).<\/p>\n<p>Many of the subdoc operations are smaller scale equivalents of fulldoc operations. It helps to think of a single document as being itself a miniature key-value store. In the Python SDK, operations can be specified via special functions in the <code>couchbase.subdocument<\/code> module, which I will abbreviate in the rest of this blog as <code>SD<\/code>. This is done by<\/p>\n<pre><code class=\"language-python\">import couchbase.subdocument as SD<\/code><\/pre>\n<p>While looking at these operations, note that what is being transmitted over the network is only the arguments passed to the subdoc API itself, rather than the contents of the entire document (as would be with fulldoc). While the document itself may seem small, even a simple<\/p>\n<h3 id=\"toc_1\">Lookup Operations<\/h3>\n<p>Lookup operations queries the document for a certain path and returns that path. You have a choice of actually <em>retrieving<\/em> the document path using the <code>GET<\/code> operation, or simply <em>querying the existence<\/em> of the path using the <code>EXISTS<\/code> operation. The latter saves even more bandwidth by not retrieving the contents of the path if it is not needed.<\/p>\n<pre><code class=\"language-python\">rv = bucket.lookup_in('customer123', SD.get('addresses.delivery.country'))\r\ncountry = rv[0] # =&gt; 'United Kingdom'<\/code><\/pre>\n<pre><code class=\"language-python\">rv = bucket.lookup_in('customer123', SD.exists('purchases.pending[-1]'))\r\nrv.exists(0) # (check if path for first command exists): =&gt;; False<\/code><\/pre>\n<p>In the second snippet, I also show how to access the last element of an array, using the special <code>[-1]<\/code> path component.<\/p>\n<p>We can also combine these two operations:<\/p>\n<pre><code class=\"language-python\">rv = bucket.lookup_in('customer123',\r\n                  SD.get('addresses.delivery.country'),\r\n                  SD.exists('purchases.pending[-1]'))\r\nrv[0] # =&gt; 'United Kingdom'\r\nrv.exists(1) # =&gt; False\r\nrv[1] # =&gt; SubdocPathNotFoundError<\/code><\/pre>\n<h3 id=\"toc_2\">Mutation Operations<\/h3>\n<p>Mutation operations modify one or more paths in the document. These operations can be divided into several groups:<\/p>\n<ul>\n<li>Dictionary\/Object operations: These operations write the value of a JSON dictionary key.<\/li>\n<li>Array\/List operations: These operations add operations to JSON array\/list.<\/li>\n<li>Generic operations: These operations modify the existing value itself and are container-agnostic.<\/li>\n<\/ul>\n<p>Mutation operations are <em>all or nothing<\/em>, meaning that either all the operations within <code>mutate_in<\/code> are successful, or none of them are.<\/p>\n<h4 id=\"toc_3\">Dictionary operations<\/h4>\n<p>The simplest of these operations is <code>UPSERT<\/code>. Just like the fulldoc-level upsert, this will either modify the value of an existing path or create it if it does not exist:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.upsert('fax', '775-867-5309'))<\/code><\/pre>\n<p>In addition to <code>UPSERT<\/code>, the <code>INSERT<\/code> operation will only add the new value to the path if it does not exist.<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.insert('purchases.complete', [42, True, None]))\r\n# SubdocPathExistsError<\/code><\/pre>\n<p>While the above operation will fail, note that anything valid as a full-doc value is also valid as a subdoc value: As long as it can be serialized as JSON. The Python SDK serializes the above value to <code>[42, true, null]<\/code>.<\/p>\n<p>Dictionary values can also be replaced or removed:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123',\r\n                 SD.remove('addresses.billing'),\r\n                 SD.replace('email', 'doug96@hotmail.com'))<\/code><\/pre>\n<h4 id=\"toc_4\">Array Operations<\/h4>\n<p>True array append (<code>ARRAY_APPEND<\/code>) and prepend (<code>ARRAY_PREPEND<\/code>) operations can also be performed using subdoc. Unlike fulldoc append\/prepend operations (which simply concatenate bytes to the existing value), subdoc append and prepend are JSON-aware:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.array_append('purchases.complete', 777))\r\n# purchases.complete is now [339, 976, 442, 666, 777]<\/code><\/pre>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.array_prepend('purchases.abandoned', 18))\r\n# purchaes.abandoned in now [18, 157, 49, 999]<\/code><\/pre>\n<p>You can make an array-only document as well, and then perform <code>array_<\/code> operations using an empty path:<\/p>\n<pre><code class=\"language-python\">bucket.upsert('my_array', [])\r\nbucket.mutate_in('my_array', SD.array_append('', 'some element'))\r\n# the document my_array is now [\"some element\"]<\/code><\/pre>\n<p>Limited support also exists for treating arrays like unique sets, using the <code>ARRAY_ADDUNIQUE<\/code> command. This will do a check to determine if the given value exists or not before actually adding the item to the array:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.array_addunique('purchases.complete', 95))\r\n# =&gt; Success\r\nbucket.mutate_in('customer123', SD.array_addunique(\u2018purchases.abandoned', 42))\r\n# =&gt;\r\n SubdocPathExists exception!<\/code><\/pre>\n<p>Array operations can also be used as the basis for efficient FIFO or LIFO queues. First, create the queue:<\/p>\n<pre><code class=\"language-python\">bucket.upsert('my_queue', [])<\/code><\/pre>\n<p>Adding items to the end<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('my_queue', SD.array_append('', 'job:953'))<\/code><\/pre>\n<p>Consuming item from beginning.<\/p>\n<pre><code class=\"language-python\">rv = bucket.lookup_in('my_queue', SD.get('[0]'))\r\njob_id = rv[0]\r\nbucket.mutate_in('my_queue', SD.remove('[0]'), cas=rv.cas)\r\nrun_job(job_id)<\/code><\/pre>\n<p>The example above performs a <code>GET<\/code> followed by a <code>REMOVE<\/code>. The <code>REMOVE<\/code> is only performed once the application already has the job, and it will only succeed if the document has not since changed (to ensure that the first item in the queue is the one we&#8217;ve just removed).<\/p>\n<h4 id=\"toc_5\">Counter Operations<\/h4>\n<p>Counter operations allow the manipulation of a <em>numeric<\/em> value inside a document. These operations are logically similar to the <code>counter<\/code> operation on an entire document.<\/p>\n<pre><code class=\"language-python\">rv = bucket.mutate_in('customer123', SD.counter('logins', 1))\r\ncur_count = rv[0] # =&gt; 1<\/code><\/pre>\n<p>The <code>COUNTER<\/code> operation peforms simple arithmetic against a numeric value (the value is created if it does not yet exist).<\/p>\n<p><code>COUNTER<\/code> can also decrement as well:<\/p>\n<pre><code class=\"language-python\">bucket.upsert('player432', {'gold': 1000})\r\nrv = bucket.mutate_in('player432', SD.counter('gold', -150))\r\nprint('player432 now has {0} gold remaining'.format(rv[0]))\r\n# =&gt; player 432 now has 850 gold remaining<\/code><\/pre>\n<p>Note that the existing value for counter operations must be within range of a 64 bit signed integer.<\/p>\n<h4 id=\"toc_6\">Creation of Intermediates<\/h4>\n<p>All of the examples above refer to creating a single new field within an existing dictionary. Creating a new hierarchy however will result in an error:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123',\r\n                 SD.upsert('phone.home', {'num': '775-867-5309', 'ext': 16}))\r\n# =&gt; SubdocPathNotFound<\/code><\/pre>\n<p>Despite the operation being an <code>UPSERT<\/code>, subdoc will refuse to create missing hierarchies by default. The <code>create_parents<\/code> option however allows it to succeed: add the protocol level the option is called <code>F_MKDIRP<\/code>, like the <code>-p<\/code> option of the <code>mkdir<\/code> command on Unix-like platforms.<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123',\r\n                 SD.upsert('phone.home',\r\n                           {'num': '775-867-5309', 'ext': 16},\r\n                           create_parents=True))<\/code><\/pre>\n<h3 id=\"toc_7\">Subdocument and CAS<\/h3>\n<p>Subdoc mostly eliminates the need for tracking <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.0\/developer-guide\/cas-concurrency.html\">CAS<\/a>. Subdoc operations are atomic and therefore if two different threads access two different sub-documents then no conflict will arise. For example the following two blocks can execute concurrently without any risk of conflict:<\/p>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.array_append('purchases.complete', 999))<\/code><\/pre>\n<pre><code class=\"language-python\">bucket.mutate_in('customer123', SD.array_append(\u2018purchases.abandoned', 998))<\/code><\/pre>\n<p>Even when modifying the <em>same<\/em> part of the document, operations will not necessarily conflict, for example two concurrent <code>ARRAY_PREPEND<\/code> to the same array will both succeed, never overwriting the other.<\/p>\n<p>This does not mean that CAS is no longer required &#8211; sometimes it&#8217;s important to ensure the <em>entire document<\/em> didn&#8217;t change state since the last operation: this is especially important with the case of <code>REMOVE<\/code> operations to ensure that the element being removed was not already replaced by something else.<\/p>\n<h3 id=\"toc_8\">FAQ about Sub-Document Operations in Couchbase<\/h3>\n<p>Over the course of developing subdoc, I&#8217;ve been asked several questions about what it does, and I&#8217;ll respond in turn:<\/p>\n<h5 id=\"toc_9\">What&#8217;s the difference between Subdoc and N1QL?<\/h5>\n<p>N1QL is a rich, expressive query language which allows you to search for and possibly mutate <em>multiple documents<\/em> at once. Subdoc is a high performance API\/implementation designed for searching within a <em>single document<\/em>.<\/p>\n<p>Subdoc is a <em>high performance<\/em> set of <em>simple, discreet APIs<\/em> for accessing data within a single document, with a goal of reducing <em>network bandwidth<\/em> and increasing overall throughput. It is implemented as part of the KV service and is therefore strongly consistent with it.<\/p>\n<p>N1QL is a <em>rich query language<\/em> capable of searching multiple documents within Couchbase which adhere to certain criteria. It operates <em>outside<\/em> the KV service, making optimized KV and index requests to satisfy incoming queries. Consistency with the KV service is configurable per query (for example, the <code>USE KEYS<\/code> clause and the <code>scan_consistency<\/code> option).<\/p>\n<h5 id=\"toc_10\">When should I use N1QL and when should I use subdoc?<\/h5>\n<p>N1QL answers questions such as <em>Find me all documents where X=42 and Y=77<\/em> whereas subdoc answers questions such as <em>Fetch X and Y from document Z<\/em>. More specifically, subdoc should be used when all the Document IDs are known (in other words, if a N1QL query contains <code>USE KEYS<\/code> it may be a candidate for subdoc).<\/p>\n<p>The two are not mutually exclusive however, and it is possible to use both N1QL and subdoc in an application.<\/p>\n<h5 id=\"toc_11\">Are <code>mutate_in<\/code> and <code>lookup_in<\/code> atomic?<\/h5>\n<p>Yes, they are atomic. Both these operations are guaranteed to have all their sub-commands (e.g. <code>COUNTER<\/code>, <code>GET<\/code>, <code>EXISTS<\/code>, <code>ADD_UNIQUE<\/code>) operate on the same version of the document.<\/p>\n<h5 id=\"toc_12\">How do I access multiple documents with subdoc?<\/h5>\n<p>There is no bona fide <em>multi<\/em> operation for subdoc, as subdoc operates within the scope of a single document. Because documents are sharded across the cluster (this is common to Couchbase and all other NoSQL stores), multi operations would not be able to guarantee the same level of transactions and atomicity between documents.<\/p>\n<h5 id=\"toc_13\">I don&#8217;t like the naming convention for arrays. Why didn&#8217;t you use <code>append<\/code>, <code>add<\/code>, etc.?<\/h5>\n<p>There are many languages out there and it seems all of them have a different idea of how to call array access functions:<\/p>\n<ul>\n<li>Generic: add to end, add to front<\/li>\n<li>C++: <code>push_back()<\/code>, <code>push_front()<\/code><\/li>\n<li>Python: <code>append()<\/code>, <code>insert(0)<\/code>, <code>extend<\/code><\/li>\n<li>Perl, Ruby, Javascript, PHP: <code>push()<\/code>, <code>unshift()<\/code><\/li>\n<li>Java, C#: <code>add()<\/code><\/li>\n<\/ul>\n<p>The term <code>append<\/code> is already used in Couchbase to refer to the full-document byte concatenation, so I considered it inconsistent to use this term in yet a different manner in subdoc.<\/p>\n<h5 id=\"toc_14\">Why does <code>COUNTER<\/code> require 64 bit signed integers?<\/h5>\n<p>This is a result of the subdoc code being implemented in C++. Future implementations may allow a broader range of existing numeric values (for example, large values, non-integral values, etc.).<\/p>\n<h5 id=\"toc_15\">How do i perform a <em>pop<\/em>? why is there no <code>POP<\/code> operation?<\/h5>\n<p><code>POP<\/code> refers to the act of removing an item (e.g. from an array) and returning it, in a single operation.<\/p>\n<p><code>POP<\/code> may indeed be implemented in the future, but using it is inherently dangerous:<\/p>\n<p>Because the operation is being done over the network, it is possible for the server to have executed the removal of the item but have the network connection terminated before the client receives the previous value. Because the value is no longer in the document, it is permanently lost.<\/p>\n<h5 id=\"toc_16\">Can I use CAS with subdoc operations?<\/h5>\n<p>Yes, in respect to CAS usage, Subdoc operations are normal KV API operations, similar to <code>upsert<\/code>, <code>get<\/code>, etc.<\/p>\n<h5 id=\"toc_17\">Can I use durability requirements with subdoc operations?<\/h5>\n<p>Yes, in respect to durability requirements, <code>mutate_in<\/code> is seen like <code>upsert<\/code>, <code>insert<\/code> and <code>replace<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Matthew&#8217;s blog the Sub-Document (subdoc) API feature is introduced with a short overview: In summary, subdoc allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network. Throughout this blog, we&#8217;ll [&hellip;]<\/p>\n","protected":false},"author":38,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1816],"tags":[1587],"ppma_author":[8997],"class_list":["post-2174","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-server","tag-subdoc"],"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>Sub-Document API: Using Subdoc to Get (Only) What You Want<\/title>\n<meta name=\"description\" content=\"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.\" \/>\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\/subdoc-explained\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using the Sub-Document API to get (only) what you want\" \/>\n<meta property=\"og:description\" content=\"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2016-07-28T18:54:41+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-11-04T23:06:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Mark Nunberg, Software Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mark Nunberg, Software Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\"},\"author\":{\"name\":\"Mark Nunberg, Software Engineer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/76a75284da32b6f257c8e5e156e6e016\"},\"headline\":\"Using the Sub-Document API to get (only) what you want\",\"datePublished\":\"2016-07-28T18:54:41+00:00\",\"dateModified\":\"2022-11-04T23:06:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\"},\"wordCount\":1638,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"subdoc\"],\"articleSection\":[\"Couchbase Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\",\"name\":\"Sub-Document API: Using Subdoc to Get (Only) What You Want\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2016-07-28T18:54:41+00:00\",\"dateModified\":\"2022-11-04T23:06:32+00:00\",\"description\":\"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#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\/subdoc-explained\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using the Sub-Document API to get (only) what you want\"}]},{\"@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\/76a75284da32b6f257c8e5e156e6e016\",\"name\":\"Mark Nunberg, Software Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/895cad0986a0ab674fda857b6ba71ce0\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g\",\"caption\":\"Mark Nunberg, Software Engineer, Couchbase\"},\"description\":\"Mark Nunberg is a software engineer working at Couchbase. He maintains the C client library (libcouchbase) as well as the Python client. He also developed the Perl client (for use at his previous company) - which initially led him to working at Couchbase. Prior to joining Couchbase, he worked on distributed and high performance routing systems at an eCommerce analytics firm. Mark studied Linguistics at the Hebrew University of Jerusalem.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/mark-nunberg\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Sub-Document API: Using Subdoc to Get (Only) What You Want","description":"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.","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\/subdoc-explained\/","og_locale":"en_US","og_type":"article","og_title":"Using the Sub-Document API to get (only) what you want","og_description":"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.","og_url":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/","og_site_name":"The Couchbase Blog","article_published_time":"2016-07-28T18:54:41+00:00","article_modified_time":"2022-11-04T23:06:32+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"Mark Nunberg, Software Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Mark Nunberg, Software Engineer, Couchbase","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/"},"author":{"name":"Mark Nunberg, Software Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/76a75284da32b6f257c8e5e156e6e016"},"headline":"Using the Sub-Document API to get (only) what you want","datePublished":"2016-07-28T18:54:41+00:00","dateModified":"2022-11-04T23:06:32+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/"},"wordCount":1638,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["subdoc"],"articleSection":["Couchbase Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/","url":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/","name":"Sub-Document API: Using Subdoc to Get (Only) What You Want","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2016-07-28T18:54:41+00:00","dateModified":"2022-11-04T23:06:32+00:00","description":"The Subdoc API feature allows efficient access to parts of documents (sub-documents) without requiring the transfer of the entire document over the network.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/subdoc-explained\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/subdoc-explained\/#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\/subdoc-explained\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using the Sub-Document API to get (only) what you want"}]},{"@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\/76a75284da32b6f257c8e5e156e6e016","name":"Mark Nunberg, Software Engineer, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/895cad0986a0ab674fda857b6ba71ce0","url":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","caption":"Mark Nunberg, Software Engineer, Couchbase"},"description":"Mark Nunberg is a software engineer working at Couchbase. He maintains the C client library (libcouchbase) as well as the Python client. He also developed the Perl client (for use at his previous company) - which initially led him to working at Couchbase. Prior to joining Couchbase, he worked on distributed and high performance routing systems at an eCommerce analytics firm. Mark studied Linguistics at the Hebrew University of Jerusalem.","url":"https:\/\/www.couchbase.com\/blog\/author\/mark-nunberg\/"}]}},"authors":[{"term_id":8997,"user_id":38,"is_guest":0,"slug":"mark-nunberg","display_name":"Mark Nunberg, Software Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","author_category":"","last_name":"Nunberg","first_name":"Mark","job_title":"","user_url":"","description":"Mark Nunberg is a software engineer working at Couchbase. He maintains the C client library (libcouchbase) as well as the Python client. He also developed the Perl client (for use at his previous company) - which initially led him to working at Couchbase. Prior to joining Couchbase, he worked on distributed and high performance routing systems at an eCommerce analytics firm. Mark studied Linguistics at the Hebrew University of Jerusalem."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2174","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\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=2174"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2174\/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=2174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2174"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}