{"id":8407,"date":"2020-04-13T00:33:48","date_gmt":"2020-04-13T07:33:48","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=8407"},"modified":"2025-06-13T17:21:46","modified_gmt":"2025-06-14T00:21:46","slug":"flexible-query-indexing-for-flexible-json-model","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/","title":{"rendered":"Flexible Query &amp; Indexing for Flexible JSON Model."},"content":{"rendered":"<blockquote>\n<h4>Use N1QL when you&#8217;re in a JSON pickle. &#8212; Confucius<\/h4>\n<\/blockquote>\n<p>For the JSON data model, the advice is to think of collections as tables, JSON document as denormalized rows and field names as columns &#8211; roughly. All this holds in databases like Couchbase and MongoDB when the recommendations are strictly followed. <span style=\"font-weight: 400\">There are many reasons why users don\u2019t simply follow this key-value pair model <\/span><i><span style=\"font-weight: 400\">all the time. <\/span><\/i><span style=\"font-weight: 400\">Here are the main reasons.\u00a0<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none\">\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">JSON is <a href=\"https:\/\/dzone.com\/articles\/keep-calm-and-json\">too verbose<\/a>.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">You want to convert a map\/hashmap data structure where the keys are dynamic.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Timeseries data when the field names are usually encoded timestamps.<\/span><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/dzone.com\/articles\/keep-calm-and-json\"><span style=\"font-weight: 400\">Dictionary based encoding<\/span><\/a><\/li>\n<li>Existing document formats and standards disallow redesign<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>If your database and query language the query language doesn&#8217;t deal with the situation, you&#8217;ve to go through an elaborate redesign.\u00a0 In addition to simply accessing the information, <span style=\"font-weight: 400\">how do you make the queries on JSON efficient when you <\/span><span style=\"font-weight: 400\">don\u2019t even know the name of the field you&#8217;ve to index on? <\/span><span style=\"font-weight: 400\"> Fortunately,\u00a0Couchbase N1QL has a variety of query and index features to deal with flexible metadata as well. <\/span><\/p>\n<p><span style=\"font-weight: 400\">Let&#8217;s consider these use cases.<\/span><\/p>\n<h4>Use Case 1: Value transformation.<\/h4>\n<p>Here&#8217;s a sample JSON document.<\/p>\n<pre title=\"Sample JSON document\" class=\"theme:dark-terminal font-size:17 line-height:20 lang:js decode:true\">{\r\n    \"cname\": \"Jane Smith\",\r\n    \"dob\" : \"1990-01-30\",\r\n    \"phones\" : [\r\n    \"+1 510-523-3529\", \"+1 650-392-4923\"\r\n    ],\r\n    \"billing\": [\r\n      {\r\n        \"type\": \"visa\",\r\n        \"cardnum\": \"5827-2842-2847-3909\",\r\n        \"expiry\": \"2019-03\"\r\n      }, \r\n      {\r\n        \"type\": \"master\",\r\n        \"cardnum\": \"6274-2542-5847-3949\",\r\n        \"expiry\": \"2018-12\"\r\n      }\r\n    ]\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400\">JSON data model is described simply as a set of key-value pairs.\u00a0 Each key is a string, unique at that its level of the hierarchy and value can be scalars, objects or arrays.\u00a0 A rigorous definition can be read <\/span><a href=\"https:\/\/tools.ietf.org\/id\/draft-handrews-json-schema-00.html\"><span style=\"font-weight: 400\">here<\/span><\/a><span style=\"font-weight: 400\">. JSON is also self-describing and that makes it flexible for a <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-for-oracle-developers-part-4-data-types\/\"><span style=\"font-weight: 400\">database document model<\/span><\/a><span style=\"font-weight: 400\">. Not every customer has to have a fixed number of telephone numbers or cars or any other type of attributes.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">The same information above can be reorganized as the JSON below without loss of information, but some implicit sche<\/span><\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:2 lang:js decode:true\">{\r\n    \"Jane Smith\": \"1990-01-30\",\r\n    \"home\": \"+1 510-523-3529\",\r\n    \"office\": \"+1 650-392-4923\",\r\n    \"Billing\": [\r\n      {\r\n        \"visa\": \"5827-2842-2847-3909\",\r\n        \"expiry\": \"2019-03\"\r\n      }, \r\n      {\r\n        \"master\": \"6274-2542-5847-3949\",\r\n        \"expiry\": \"2018-12\"\r\n      }\r\n    ]\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400\">This is all well and good if you\u2019re simply putting and setting the document.\u00a0 It doesn\u2019t matter what the structure of JSON. Simply schlep is back and forth.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Now, let\u2019s see how this affects querying.<\/span><\/p>\n<p><span class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:1 whitespace-after:1 lang:mysql decode:true crayon-inline\">Q1: SELECT * FROM customers WHERE cxname = \u201cJane Smith\u201d; <\/span><\/p>\n<p><span style=\"font-weight: 400\">With the new JSON model, there isn\u2019t a field name called <strong>cxname<\/strong>\u00a0here.<\/span><\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:1 whitespace-after:1 lang:mysql decode:true\">Q2: SELECT p FROM people p \r\nWHERE ANY o IN object_names(p) SATISFIES o = \"Jane Smith\" END<\/pre>\n<p><span style=\"font-weight: 400\">What the magic of <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/objectfun.html#object_pairsexpression\"><span style=\"font-weight: 400\">object_pairs()<\/span><\/a><span style=\"font-weight: 400\"> function?\u00a0 This transforms the JSON {\u201ckey\u201d:\u201dvalue\u201d} pairs into an array of name-value pairs.\u00a0 Here\u2019s an example.<\/span><\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 top-margin:20 whitespace-before:1 whitespace-after:1 lang:mysql decode:true\">SELECT OBJECT_NAMES({\"Jane Smith\": \"1990-01-30\", \"home\": \"+1 510-523-3529\"})\r\n\r\n    \"$1\": [\r\n      \"Jane Smith\",\r\n      \"home\"\r\n    ]\r\n  }\r\n<\/pre>\n<p>The OBJECT_NAMES() function extracts the key (here \u201cJane Smith\u201d) and returns as a value, which then can be indexed. Since the function returns not just one value, but an array of \u201ckey names\u201d as values, you need to create an array index.\u00a0 <span style=\"font-weight: 400\">Queries Q1 and Q2 do the same job for the respective data model.\u00a0 But, we need each of those queries to execute in milliseconds.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">For Q1, we simply create the index on cxname.<\/span><\/p>\n<p><span class=\"theme:dark-terminal font-size:17 line-height:20 lang:mysql decode:true crayon-inline\">CREATE INDEX ix_cxname ON customers(cxname)<\/span><\/p>\n<p><span style=\"font-weight: 400\">For Q2,\u00a0\u00a0<\/span><\/p>\n<p><span class=\"theme:dark-terminal font-size:17 line-height:20 lang:mysql decode:true crayon-inline\">CREATE INDEX ix_people ON people(DISTINCT OBJECT_NAMES(self))<\/span><\/p>\n<p>With this index, for Q2, you&#8217;ll get a plan that uses the index.<\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:1 whitespace-after:1 lang:js decode:true \">        {\r\n            \"#operator\": \"DistinctScan\",\r\n            \"scan\": {\r\n                \"#operator\": \"IndexScan3\",\r\n                \"as\": \"p\",\r\n                \"cardinality\": 1,\r\n                \"cost\": 0.273,\r\n                \"index\": \"ix_people\",\r\n                \"index_id\": \"4a2df8dd85543aa4\",\r\n                \"index_projection\": {\r\n                    \"primary_key\": true\r\n                },\r\n                \"keyspace\": \"people\",\r\n                \"namespace\": \"default\",\r\n                \"spans\": [\r\n                    {\r\n                        \"exact\": true,\r\n                        \"range\": [\r\n                            {\r\n                                \"high\": \"\\\"Jane Smith\\\"\",\r\n                                \"inclusion\": 3,\r\n                                \"low\": \"\\\"Jane Smith\\\"\"\r\n                            }\r\n                        ]\r\n                    }\r\n                ],<\/pre>\n<p>&nbsp;<\/p>\n<h4>Use Case 2: Dynamic Key names.<\/h4>\n<p>This is use case is taken from the <span style=\"font-weight: 400\">Couchbase <\/span><a href=\"https:\/\/www.couchbase.com\/forums\/t\/indexing-object-with-dynamic-keys-within-a-document\/24526\/2\/\"><span style=\"font-weight: 400\">forum post.<\/span><\/a><\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:2 lang:js decode:true \">{\r\n    \"id\": \"05a9b954-bdee-4d7f-9715-8e9e08f8cb75\",\r\n    \"type\": \"article\",\r\n    \"translations\": {\r\n        \"en\": \"Hello\",\r\n        \"de\": \"Hallo\", \r\n        \"fr\": \"Bonjour\",\r\n        \"es\": \"Hola\"\r\n    }\r\n}<\/pre>\n<p><span style=\"font-weight: 400\"><strong>Question:<\/strong> <\/span><span style=\"font-weight: 400\">What would be the best way to index the values within <\/span><strong>translations<\/strong><span style=\"font-weight: 400\"><strong> dynamically<\/strong>? I.e. a generic index that indexes all keys within the <\/span><span style=\"font-weight: 400\">translations<\/span><span style=\"font-weight: 400\"> object. <\/span><\/p>\n<p><span style=\"font-weight: 400\">If the need is to simply query for English documents all the time,\u00a0 to <\/span><span style=\"font-weight: 400\">query all documents that have <\/span><span style=\"font-weight: 400\">translations.en = &#8220;Hello&#8221;<\/span><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">If you\u2019re always looking for translations to English, you can simply create the index on transactions.en.<\/span><\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:1 whitespace-after:1 lang:mysql decode:true\">CREATE INDEX ix_tren ON info(translations.en);\r\nSELECT * FROM info WHERE translation.en = \u201cHello\u201d;<\/pre>\n<p>If the keys are dynamic, you don&#8217;t know what specific language is going to be in the data and which ones can be queries upon, you&#8217;ve to make them both dynamic.<\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:1 whitespace-after:1 lang:mysql decode:true\">\/* Query *\/\r\nSELECT *\r\nFROM info\r\n    WHERE  ANY v IN OBJECT_PAIRS(translations) \r\n            SATISFIES [v.name,v.val] = [\"en\", \"Hello\"] \r\n        END\r\n\r\n\/* Index *\/\r\nCREATE INDEX ix_infoname ON info (\r\n    DISTINCT ARRAY [v.name, v.val ]\r\n    FOR v IN OBJECT_PAIRS(translations) END\r\n)<\/pre>\n<p>Here&#8217;s the explain to verify that the index is indeed picked up and the predicates are pushed down to the index scan.<\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 whitespace-before:2 whitespace-after:2 lang:js decode:true\">        {\r\n            \"#operator\": \"DistinctScan\",\r\n            \"scan\": {\r\n                \"#operator\": \"IndexScan3\",\r\n                \"cardinality\": 0.5,\r\n                \"cost\": 0.1665,\r\n                \"index\": \"ix_infoname\",\r\n                \"index_id\": \"bebbfd22a022fb75\",\r\n                \"index_projection\": {\r\n                    \"primary_key\": true\r\n                },\r\n                \"keyspace\": \"info\",\r\n                \"namespace\": \"default\",\r\n                \"spans\": [\r\n                    {\r\n                        \"exact\": true,\r\n                        \"range\": [\r\n                            {\r\n                                \"high\": \"[\\\"en\\\", \\\"Hello\\\"]\",\r\n                                \"inclusion\": 3,\r\n                                \"low\": \"[\\\"en\\\", \\\"Hello\\\"]\"\r\n                            }\r\n                        ]\r\n                    }\r\n                ],\r\n                \"using\": \"gsi\"\r\n            }\r\n        },<\/pre>\n<p>Not to worry, if the index definition looks a bit more complicated than normal.\u00a0 The Index Advisor has your covered.<\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 wrap:true whitespace-before:2 whitespace-after:2 lang:mysql decode:true\">ADVISE SELECT * \r\n       FROM info \r\n       WHERE ANY v IN OBJECT_PAIRS(translations) \r\n                 SATISFIES [v.name,v.val] = [\"en\", \"Hello\"] \r\n       END\r\n\r\n\r\n{\r\n    \"index_statement\": \"CREATE INDEX adv_DISTINCT_object_pairs_translations_name_val ON `info`(DISTINCT ARRAY [`v`.`name`, `v`.`val`] FOR v in object_pairs((`translations`)) END)\",\r\n    \"keyspace_alias\": \"info\",\r\n    \"recommending_rule\": \"Index keys follow order of predicate types: 2. equality\/null\/missing.\"\r\n}<\/pre>\n<p>You can even add expressions on top of each expression you&#8217;re evaluating.<\/p>\n<pre class=\"theme:dark-terminal font-size:17 line-height:20 wrap:true whitespace-before:2 whitespace-after:2 lang:mysql decode:true\">ADVISE SELECT * \r\n       FROM info \r\n       WHERE ANY v IN OBJECT_PAIRS(translations) \r\n                 SATISFIES [LOWER(v.name),LOWER(v.val)] = [\"en\", \"Hello\"] \r\n       END\r\n\r\n\r\n{\r\n      \"index_statement\": \"CREATE INDEX adv_DISTINCT_object_pairs_translations_lower_name_lower_val ON `info`(DISTINCT ARRAY [lower((`v`.`name`)), lower((`v`.`val`))] FOR v in object_pairs((`translations`)) END)\",\r\n      \"keyspace_alias\": \"info\",\r\n      \"recommending_rule\": \"Index keys follow order of predicate types: 2. equality\/null\/missing.\"\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>More Object Functions<\/strong><\/h4>\n<p>N1QL has additional <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/objectfun.html\">object<\/a> and nested data functions to help with complex data models.\u00a0 Check out the full set of object functions and the <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/tokenfun.html\">token functions<\/a>.<\/p>\n<p><b>References:<\/b><\/p>\n<ol>\n<li>Couchbae N1QL Object Functions <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/objectfun.html\">Documentation<\/a><\/li>\n<li>Couchbase <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/indexing-arrays.html\">Array indexing\u00a0<\/a><\/li>\n<li>Couchbase <a href=\"https:\/\/www.couchbase.com\/blog\/create-right-index-get-right-performance\/\">index blog<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Use N1QL when you&#8217;re in a JSON pickle. &#8212; Confucius For the JSON data model, the advice is to think of collections as tables, JSON document as denormalized rows and field names as columns &#8211; roughly. All this holds in [&hellip;]<\/p>\n","protected":false},"author":55,"featured_media":8408,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1815,2453,1812],"tags":[1447,1505,1261],"ppma_author":[8929],"class_list":["post-8407","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-best-practices-and-tutorials","category-global-secondary-index","category-n1ql-query","tag-data-modeling","tag-index","tag-json"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Flexible Query &amp; Indexing for Flexible JSON Model. - The Couchbase Blog<\/title>\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\/flexible-query-indexing-for-flexible-json-model\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Flexible Query &amp; Indexing for Flexible JSON Model.\" \/>\n<meta property=\"og:description\" content=\"Use N1QL when you&#8217;re in a JSON pickle. &#8212; Confucius For the JSON data model, the advice is to think of collections as tables, JSON document as denormalized rows and field names as columns &#8211; roughly. All this holds in [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-04-13T07:33:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T00:21:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1130\" \/>\n\t<meta property=\"og:image:height\" content=\"755\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Keshav Murthy\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@rkeshavmurthy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Keshav Murthy\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\"},\"author\":{\"name\":\"Keshav Murthy\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c261644262bf98e146372fe647682636\"},\"headline\":\"Flexible Query &amp; Indexing for Flexible JSON Model.\",\"datePublished\":\"2020-04-13T07:33:48+00:00\",\"dateModified\":\"2025-06-14T00:21:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\"},\"wordCount\":714,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg\",\"keywords\":[\"Data Modeling\",\"Index\",\"JSON\"],\"articleSection\":[\"Application Design\",\"Best Practices and Tutorials\",\"Global Secondary Index\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\",\"name\":\"Flexible Query &amp; Indexing for Flexible JSON Model. - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg\",\"datePublished\":\"2020-04-13T07:33:48+00:00\",\"dateModified\":\"2025-06-14T00:21:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg\",\"width\":1130,\"height\":755},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Flexible Query &amp; Indexing for Flexible JSON Model.\"}]},{\"@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\/c261644262bf98e146372fe647682636\",\"name\":\"Keshav Murthy\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4e51d72fc07c662aa791316deafffac4\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g\",\"caption\":\"Keshav Murthy\"},\"description\":\"Keshav Murthy is a Vice President at Couchbase R&amp;D. Previously, he was at MapR, IBM, Informix, Sybase, with more than 20 years of experience in database design &amp; development. He lead the SQL and NoSQL R&amp;D team at IBM Informix. He has received two President's Club awards at Couchbase, two Outstanding Technical Achievement Awards at IBM. Keshav has a bachelor's degree in Computer Science and Engineering from the University of Mysore, India, holds eleven US patents and has four US patents pending.\",\"sameAs\":[\"https:\/\/blog.planetnosql.com\/\",\"https:\/\/x.com\/rkeshavmurthy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/keshav-murthy\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Flexible Query &amp; Indexing for Flexible JSON Model. - The Couchbase Blog","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\/flexible-query-indexing-for-flexible-json-model\/","og_locale":"en_US","og_type":"article","og_title":"Flexible Query &amp; Indexing for Flexible JSON Model.","og_description":"Use N1QL when you&#8217;re in a JSON pickle. &#8212; Confucius For the JSON data model, the advice is to think of collections as tables, JSON document as denormalized rows and field names as columns &#8211; roughly. All this holds in [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/","og_site_name":"The Couchbase Blog","article_published_time":"2020-04-13T07:33:48+00:00","article_modified_time":"2025-06-14T00:21:46+00:00","og_image":[{"width":1130,"height":755,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg","type":"image\/jpeg"}],"author":"Keshav Murthy","twitter_card":"summary_large_image","twitter_creator":"@rkeshavmurthy","twitter_misc":{"Written by":"Keshav Murthy","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/"},"author":{"name":"Keshav Murthy","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c261644262bf98e146372fe647682636"},"headline":"Flexible Query &amp; Indexing for Flexible JSON Model.","datePublished":"2020-04-13T07:33:48+00:00","dateModified":"2025-06-14T00:21:46+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/"},"wordCount":714,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg","keywords":["Data Modeling","Index","JSON"],"articleSection":["Application Design","Best Practices and Tutorials","Global Secondary Index","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/","url":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/","name":"Flexible Query &amp; Indexing for Flexible JSON Model. - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg","datePublished":"2020-04-13T07:33:48+00:00","dateModified":"2025-06-14T00:21:46+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2020\/04\/pencil.jpg","width":1130,"height":755},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/flexible-query-indexing-for-flexible-json-model\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Flexible Query &amp; Indexing for Flexible JSON Model."}]},{"@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\/c261644262bf98e146372fe647682636","name":"Keshav Murthy","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4e51d72fc07c662aa791316deafffac4","url":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","caption":"Keshav Murthy"},"description":"Keshav Murthy is a Vice President at Couchbase R&amp;D. Previously, he was at MapR, IBM, Informix, Sybase, with more than 20 years of experience in database design &amp; development. He lead the SQL and NoSQL R&amp;D team at IBM Informix. He has received two President's Club awards at Couchbase, two Outstanding Technical Achievement Awards at IBM. Keshav has a bachelor's degree in Computer Science and Engineering from the University of Mysore, India, holds eleven US patents and has four US patents pending.","sameAs":["https:\/\/blog.planetnosql.com\/","https:\/\/x.com\/rkeshavmurthy"],"url":"https:\/\/www.couchbase.com\/blog\/author\/keshav-murthy\/"}]}},"authors":[{"term_id":8929,"user_id":55,"is_guest":0,"slug":"keshav-murthy","display_name":"Keshav Murthy","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g","author_category":"","last_name":"Murthy","first_name":"Keshav","job_title":"","user_url":"https:\/\/blog.planetnosql.com\/","description":"Keshav Murthy is a Vice President at Couchbase R&amp;D. Previously, he was at MapR, IBM, Informix, Sybase, with more than 20 years of experience in database design &amp; development. He lead the SQL and NoSQL R&amp;D team at IBM Informix. He has received two President's Club awards at Couchbase, two Outstanding Technical Achievement Awards at IBM. Keshav has a bachelor's degree in Computer Science and Engineering from the University of Mysore, India,  holds ten US patents and has three US patents pending."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/8407","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\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=8407"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/8407\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/8408"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=8407"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=8407"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=8407"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=8407"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}