{"id":1358,"date":"2018-07-11T23:07:33","date_gmt":"2018-07-12T06:07:33","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/joining-json-comparing-couchbase-n1ql-mongodb\/"},"modified":"2018-07-11T23:07:33","modified_gmt":"2018-07-12T06:07:33","slug":"joining-json-comparing-couchbase-n1ql-mongodb","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/joining-json-comparing-couchbase-n1ql-mongodb\/","title":{"rendered":"How to Join JSON: Couchbase N1QL vs. MongoDB Query"},"content":{"rendered":"\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-5483\" src=\"https:\/\/www.couchbase.com\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-07-13-at-1.24.12-PM-300x157-1.png\" alt=\"\" width=\"567\" height=\"297\"><\/p>\n\n\n\n<p><span>As NoSQL databases evolved, each added higher level APIs or languages to help programmers to complex things easily. SQL, having done that for relational data, showed the way. In SQL, developers say WHAT needs to be done and the database engine figures out the HOW. \u00a0HOW is the efficient procedure\/algorithm to execute the statement. <\/span><span>Select, join and project are the basic operations SQL processing. Even in NoSQL systems when you model data without much normalization, you still need to join a collection of objects. \u00a0Customers with orders, orders with inventory, inventory with suppliers, suppliers with credits and so forth. Hence, Couchbase N1QL has supported join operations since its first release. \u00a0Following that, MongoDB, in version 3.2, added $lookup operator to the aggregation framework to perform the join operations. <\/span><\/p>\n\n\n\n<p><span>Without an expressive and high-performance query feature, application developers have to do it within the application or export the data to a system that does it. \u00a0Both expensive propositions. <\/span><\/p>\n\n\n\n<p><span>In this article, we will be comparing Couchbase vs. MongoDB and their differing approaches to join JSON documents. Specifically, we do a comparative study of using joins for MongoDB collections versus how we can execute them in Couchbase. <span>Joins are unsupported in Cassandra CQL and DynamoDB natively.\u00a0 Developers must do the work themselves or use other layers like Spark or Amazon EMR to achieve the same result. So, we won\u2019t cover them in this article<\/span>.<\/span><\/p>\n\n\n\n<p><span>Joins in Couchbase<\/span><\/p>\n\n\n\n<p><span>Couchbase introduced INNER and LEFT OUTER joins starting with Couchbase 4.0 (2015). This supported joins of in a child-to-parent relationship. \u00a0Children documents (e.g. Orders) can be joined with parent documents (e.g. customer). In 4.5 (2016), Couchbase introduced <\/span><a href=\"https:\/\/dzone.com\/articles\/join-faster-with-couchbase-index-joins\"><span>index joins<\/span><\/a><span> to query from parent to child joins. \u00a0In both cases, there was an implied attribute-value to document-key equality predicate, specified by the ON KEY clause. \u00a0<\/span><\/p>\n\n\n\n<p><span>Couchbase 5.5 has ANSI standard SQL extended for JSON. \u00a0It supports INNER JOIN, LEFT OUTER JOIN and limited RIGHT OUTER join.\u00a0 We&#8217;ll be using examples based on Couchbase 5.5.<\/span><\/p>\n\n\n\n<p><span>Couchbase joins documentation: <\/span><a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/5.5\/n1ql\/n1ql-language-reference\/from.html\"><span>https:\/\/developer.couchbase.com\/documentation\/server\/5.5\/n1ql\/n1ql-language-reference\/from.html<\/span><\/a><\/p>\n\n\n\n<p><span>MongoDB Joins and Collections:<\/span><\/p>\n\n\n\n<p><span>Joins are supported via the $lookup operator within the aggregation framework. <\/span><\/p>\n\n\n\n<p><span>Following are excerpts from the MongoDB documentation.<\/span><\/p>\n\n\n\n<p><i><span>New in version 3.2.<\/span><\/i><\/p>\n\n\n\n<p><span>Performs a left outer join to an unsharded collection in the <\/span><i><span>same<\/span><\/i><span> database to filter in documents from the \u201cjoined\u201d collection for processing. To each input document, the <\/span><a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/lookup\/#pipe._S_lookup\"><span>$lookup<\/span><\/a><span> stage adds a new array field whose elements are the matching documents from the \u201cjoined\u201d collection. The <\/span><a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/lookup\/#pipe._S_lookup\"><span>$lookup<\/span><\/a><span> stage passes these reshaped documents to the next stage.<\/span><\/p>\n\n\n\n<p><span>Eliot Horowitz, MongoDB CTO, <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=MPPwn1XmhzQ\"><span>said<\/span><\/a><span>: &#8220;MongoDB aggregation is similar to Unix pipeline. The output of one stage goes into another\u2026.[it\u2019s] very procedural. Lets you think about in a very procedural way.&#8221;<\/span><\/p>\n\n\n\n<p><span>MongoDB $lookup : <\/span><a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/lookup\/\"><span>https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/lookup\/<\/span><\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Interested in learning more on JOINs? \u00a0Read the article by Lukas Eder. <a href=\"https:\/\/dzone.com\/articles\/a-probably-incomplete-comprehensive-guide-to-the-many-different-ways-to-join-tables-in-sql\">https:\/\/dzone.com\/articles\/a-probably-incomplete-comprehensive-guide-to-the-many-different-ways-to-join-tables-in-sql<\/a><\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><span>High Level Comparison between Couchbase N1Ql and MongoDB.<\/span><\/p>\n\n\n\n<p><span>Couchbase N1QL: Supports INNER JOIN, LEFT OUTER JOIN and limited RIGHT OUTER JOIN.\u00a0 The query language, like SQL, is declarative. Developers write, tools generate the query to the N1QL syntax.\u00a0 The engine figures out the plan and executes the query.<\/span><\/p>\n\n\n\n<p><span>MongoDB: Supports LEFT OUTER JOIN for scalar values only.\u00a0 The design of the joins into the MongoDB query language is done help write the query and process data in a procedural way.\u00a0<\/span><\/p>\n\n\n\n<p><span>Implication<\/span><span><span>:<\/span> <\/span><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span>Left outer join resultset is a superset of inner join resultset. \u00a0It\u2019s possible to add additional predicates to eliminate the non-matching (null-projected or missing subservient side of the join) documents after the left outer join is performed. \u00a0That\u2019s like going from San Francisco to Chicago via London. You can do it, but it&#8217;s expensive. For the query execution, it takes time, memory, cpu resources affecting the overall performance of the system.<\/span><\/li>\n\n\n<li>N1QL support for joins is declarative.\u00a0 MongoDB language is somewhat procedural.\u00a0 You&#8217;ve to separate the predicates, think about the join order between collections, think about when to\u00a0group, sort, etc.\u00a0 Writing queries with MongoDB aggregation is like writing query plans, step by step.<\/li>\n\n<\/ol>\n\n\n\n<p><span><strong>Examples:<\/strong> <\/span><\/p>\n\n\n\n<p><span>We use the simple travel-sample model and data. \u00a0Here are the details of the model data. <\/span><a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.5\/travel-app\/travel-app-data-model.html\"><span>https:\/\/developer.couchbase.com\/documentation\/server\/4.5\/travel-app\/travel-app-data-model.html<\/span><\/a><\/p>\n\n\n\n<p><span>We simply exported the data from Couchbase and imported it to a mongo database called travel-sample. \u00a0In MongoDB, the 5 different types of the document (landmark, route, airline, airport, hotel) are stored in 5 collections with respective names.<\/span><\/p>\n\n\n\n<p><span><span>Example 1<\/span><span>: LEFT OUTER JOIN with ON clause on scalar values.<\/span><\/span><\/p>\n\n\n\n<p><span>Couchbase N1QL<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;mysql&#8221; decode=&#8221;true&#8221;]SELECT count(*)<br \/>\nFROM `travel-sample` route<br \/>\n         LEFT OUTER JOIN `travel-sample` airline<br \/>\n         ON (route.airlineid = META(airline).id)<br \/>\nWHERE route.type = &#8216;route&#8217;;<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>MongoDB Query<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]db.route.aggregate([<br \/>\n   {<br \/>\n     $lookup:<br \/>\n       {<br \/>\n         from:&#8221;airline&#8221;,<br \/>\n         localField: &#8220;airlineid&#8221;,<br \/>\n         foreignField: &#8220;_id&#8221;,<br \/>\n         as: &#8220;airline_docs&#8221;<br \/>\n       }<br \/>\n   },<br \/>\n   { $group: { _id: null, myCount: { $sum: 1 } } },<br \/>\n   { $project: { _id: 0 } }<br \/>\n ]);<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Observations:<\/span><\/p>\n\n\n\n<p>This is a fairly simple left outer join query joining two collections and then simply counting the total number of documents produced.\u00a0 Notice, unlike N1QL (and SQL), in MongoDB, you&#8217;d still have to group the resultset to get the count, even if you have a single group.<\/p>\n\n\n\n<p><span>Example 2: List the airports and landmarks in the same city, ordered by the airports.<\/span><\/p>\n\n\n\n<p><span>Couchbase N1QL:<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;mysql&#8221; decode=&#8221;true&#8221;]SELECT landmark.name AS Landmark_Name,<br \/>\n       MIN(airport.airportname) AS Airport_Name,<br \/>\n       MIN(airport.tz) AS Landmark_Time<br \/>\nFROM `travel-sample` airport INNER JOIN `travel-sample` landmark<br \/>\n      ON airport.city = landmark.city<br \/>\nWHERE landmark.country = &#8220;United States&#8221;<br \/>\n      AND airport.type = &#8220;airport&#8221;<br \/>\n      AND landmark.type = &#8220;landmark&#8221;<br \/>\nGROUP BY landmark.name<br \/>\nORDER BY Airport_Name<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>MongoDB:<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]db.airport.aggregate([<br \/>\n   {<br \/>\n     $lookup:<br \/>\n       {<br \/>\n         from:&#8221;landmark&#8221;,<br \/>\n         localField: &#8220;city&#8221;,<br \/>\n         foreignField: &#8220;city&#8221;,<br \/>\n         as: &#8220;aplm_docs&#8221;<br \/>\n       }<br \/>\n   },<br \/>\n   {<br \/>\n      $match: {&#8220;airline_docs&#8221;: {$ne: []}}<br \/>\n   },<br \/>\n   {  $unwind: { path: &#8220;$aplm_docs&#8221;, preserveNullAndEmptyArrays: true }},<br \/>\n   {  $group: {<br \/>\n      _id: &#8220;$aplm_docs.name&#8221;,<br \/>\n      Airport_Name: { $min: &#8220;$airportname&#8221; } ,<br \/>\n      Landmark_Time: { $min: &#8220;$tz&#8221;}<br \/>\n     }<br \/>\n   },<br \/>\n   { $sort : { Airport_Name: 1 } },<br \/>\n   { $project: { _id: 1, Airport_Name:1, Landmark_Time:1  } }<br \/>\n ]);<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Observations:<\/span><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>This query uses INNER JOIN which MongoDB does not have.\u00a0 So, in MongoDB, you first do the lookup join to get the LEFT OUTER JOIN, and then eliminate non matching, but projected documents (because of the left outer) using the match stage (code:\u00a0$match: {&#8220;airline_docs&#8221;: {$ne: []}}).<\/li>\n\n\n<li>Then, you&#8217;ve to remember the matched documents are in an array data structure, unwind them before you group them by the landmark.name.\u00a0 \u00a0Then do the sort and final projection.<\/li>\n\n<\/ol>\n\n\n\n<p>As expected, the MongoDB join query is procedural and you&#8217;ve to understand the execution plan and write code for each stage.<\/p>\n\n\n\n<p><span>Example 3: Starting from San Francisco, find all the destination airports (those have routes from SFO).<\/span><\/p>\n\n\n\n<p><span>Couchbase N1QL<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;mysql&#8221; decode=&#8221;true&#8221;]SELECT DISTINCT route.destinationairport<br \/>\nFROM `travel-sample` airport JOIN `travel-sample` route<br \/>\n     ON (airport.faa = route.sourceairport AND route.type = &#8220;route&#8221;)<br \/>\nWHERE airport.type = &#8220;airport&#8221;<br \/>\n  AND airport.city = &#8220;San Francisco&#8221;<br \/>\n  AND airport.country = &#8220;United States&#8221;<br \/>\nORDER BY route.destinationairport<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>MongoDB:<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]db.airport.aggregate([<br \/>\n   {<br \/>\n      $match: {<br \/>\n          $and: [<br \/>\n            {&#8220;type&#8221;: &#8220;airport&#8221;},<br \/>\n            { city: &#8220;San Francisco&#8221;},<br \/>\n            { &#8220;country&#8221;: &#8220;United States&#8221;}<br \/>\n          ]<br \/>\n      }<br \/>\n   },<br \/>\n   {<br \/>\n     $lookup:<br \/>\n       {<br \/>\n         from:&#8221;route&#8221;,<br \/>\n         let: { rfaa : &#8220;$faa&#8221;},<br \/>\n         pipeline: [<br \/>\n           { $match:<br \/>\n               { $expr:<br \/>\n                 { $and:<br \/>\n                   [<br \/>\n                     { $eq: [&#8220;$sourceairport&#8221;, &#8220;$$rfaa&#8221;]} ,<br \/>\n                     { $eq: [&#8220;$type&#8221;, &#8220;route&#8221;] }<br \/>\n                   ]<\/p>\n<p>                }<br \/>\n              }<br \/>\n           }<br \/>\n         ],<br \/>\n         as: &#8220;airline_docs&#8221;<br \/>\n       }<br \/>\n   },<br \/>\n   { $match: {&#8220;airline_docs&#8221;: {$ne: []}} },<br \/>\n   {  $unwind: { path: &#8220;$airline_docs&#8221;, preserveNullAndEmptyArrays: true }},<br \/>\n   { $project: { _id:0,  &#8220;airline_docs.destinationairport&#8221; : 1 }},<br \/>\n   { $group: {<br \/>\n      _id : &#8220;$airline_docs.destinationairport&#8221;<br \/>\n     }<br \/>\n   },<br \/>\n   { $sort: { _id : 1 }},<br \/>\n ]);<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Observations:<\/span><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The join clause for this query is a bit more complex, with two predicates\u00a0(airport.faa = (route.sourceairport AND route.type = &#8220;route&#8221;).\u00a0 This requires a cumbersome pipeline syntax on the MongoDB query.<\/li>\n\n\n<li>And because you need to differentiate between the two collections, you need another let stage to create the local variables for airport attributes.<\/li>\n\n\n<li>Like before, it requires an additional match clause to eliminate non-matching (empty) airline docs, followed by grouping and sorting.<\/li>\n\n\n<li>As you can see visually, the MongoDB query is getting larger and larger to do the same job as Couchbase N1QL.<\/li>\n\n<\/ol>\n\n\n\n<p><span>Example 4: Find all the hotels and landmarks in Yosemite.\u00a0 Hotels should have <\/span>altleast<span> 5 likes.<\/span><\/p>\n\n\n\n<p><span>Couchbase N1QL<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;mysql&#8221; decode=&#8221;true&#8221;]SELECT hotel.name hotel_name, landmark.name landmark_name, landmark.activity<br \/>\nFROM `travel-sample` hotel INNER JOIN `travel-sample` landmark<br \/>\n    ON (hotel.city = landmark.city<br \/>\n        AND hotel.country = landmark.country<br \/>\n        AND landmark.type = &#8220;landmark&#8221;)<br \/>\nWHERE hotel.type = &#8220;hotel&#8221;<br \/>\n  AND hotel.title like &#8220;Yosemite%&#8221;<br \/>\n  AND array_length(hotel.public_likes) &gt; 5;<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>MongoDB:<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;js&#8221; decode=&#8221;true&#8221;]db.hotel.aggregate([<br \/>\n   { $match:  { title: { $regex: \/^Yosemite\/ } }, },<br \/>\n   {<br \/>\n     $lookup:<br \/>\n       {<br \/>\n         from:&#8221;landmark&#8221;,<br \/>\n         let: { hcity : &#8220;$city&#8221;, hcountry : &#8220;$country&#8221;},<br \/>\n         pipeline: [<br \/>\n           { $match:<br \/>\n               { $expr:<br \/>\n                 { $and:<br \/>\n                   [<br \/>\n                     { $eq: [&#8220;$city&#8221;, &#8220;$$hcity&#8221;]} ,<br \/>\n                     { $eq: [&#8220;$country&#8221;, &#8220;$$hcountry&#8221;] }<br \/>\n                   ]<br \/>\n                }<br \/>\n              }<br \/>\n           }<br \/>\n         ],<br \/>\n         as: &#8220;hotel_lm_docs&#8221;<br \/>\n       }<br \/>\n   },<br \/>\n   { $match : {&#8220;hotel_lm_docs&#8221;: { $ne: [] }}},<br \/>\n   { $project: {_id:0, hname: &#8220;$name&#8221;, public_likes: 1, hotel_lm_docs:1}},<br \/>\n   { $unwind: { path: &#8220;$hotel_lm_docs&#8221;, preserveNullAndEmptyArrays: true }},<br \/>\n   { $project: { _id: 1, hname : 1 , &#8220;hotel_lm_docs.name&#8221; : 1, &#8220;hotel_lm_docs.name&#8221; : 1, &#8220;hotel_lm_docs.activity&#8221; : 1, mt5 : {$gt: [ {$size: &#8220;$public_likes&#8221;}, 5]}}},<br \/>\n   { $match: { mt5 : true } },<br \/>\n   { $project: {_$id:0}}<br \/>\n ]);<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Observation:<\/span><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Translating the LIKE predicate into a regular expression was straightforward, but determining if there were atleast five public_likes was not.\u00a0 Needed additional projection and matching phase to calculate the size of the public_likes at the end.<\/li>\n\n\n<li>When you have many attributes to match, manipulate and project, you&#8217;d have to rename them properly at appropriate stage otherwise, the query can&#8217;t reference it.\u00a0 For example, hotel.name had to be renamed to hname\u00a0before the unwind.\u00a0 Maybe there&#8217;s a better way to write this stage!<\/li>\n\n\n<li>N1QL expressed the query in 370 characters. MongoDB required 956 characters.\u00a0 All this for a two table join.\u00a0 As the complexity increases, the ratio increases as well since the MongoDB query is written in a procedural way.<\/li>\n\n<\/ol>\n\n\n\n<p><span>Example 5: Find all the hotels and landmarks in Yosemite.\u00a0 Hotels should have at least 5 likes.<\/span><\/p>\n\n\n\n<p>This is just like Example 4, but do it faster!<\/p>\n\n\n\n<p><span>Couchbase N1QL<\/span><\/p>\n\n\n<p>[crayon theme=&#8221;github&#8221; font=&#8221;courier-new&#8221; wrap=&#8221;true&#8221; whitespace-before=&#8221;1&#8243; whitespace-after=&#8221;1&#8243; lang=&#8221;mysql&#8221; decode=&#8221;true&#8221;]SELECT hotel.name hotel_name, landmark.name landmark_name, landmark.activity<br \/>\nFROM `travel-sample` hotel INNER JOIN `travel-sample` landmark USE HASH(build)<br \/>\n    ON (hotel.city = landmark.city<br \/>\n        AND hotel.country = landmark.country<br \/>\n        AND landmark.type = &#8220;landmark&#8221;)<br \/>\nWHERE hotel.type = &#8220;hotel&#8221;<br \/>\n  AND hotel.title like &#8220;Yosemite%&#8221;<br \/>\n  AND array_length(hotel.public_likes) &gt; 5;<br \/>\n[\/crayon]<\/p>\n\n\n\n<p><span>Observation:<\/span><\/p>\n\n\n\n<p>The default join method in Couchbase N1QL is nested loop join.\u00a0 This works fine when you have a smaller number of documents involved on each side of the join.\u00a0 When you have a\u00a0larger data set, typically in reporting queries, nested loop join slows down.\u00a0 Couchbase N1QL has hash joins and this speeds up joins significantly.\u00a0 When each side of join has thousands of documents to millions of documents, the speed increase can be 2x to 20x or more.\u00a0See the <a href=\"https:\/\/www.couchbase.com\/blog\/ansi-join-support-n1ql\/\">detailed Couchbase blog<\/a> on ANSI Joins for more information.<\/p>\n\n\n\n<p>From the documentation and explain plan, it&#8217;s unclear what join method MongoDB uses. Some of the blogs indicate that they&#8217;ve used a nested loop join to implement the $lookup operator.<\/p>\n\n\n\n<p><strong>Summary:<\/strong><\/p>\n\n\n\n<p>\u00a0<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<tbody>\n<tr>\n<td><\/td>\n<td><span><b>Couchbase N1QL<\/b><\/span><\/td>\n<td><span><b>MongoDB<\/b><\/span><\/td>\n<\/tr>\n<tr>\n<td><b>JOIN approach<\/b><\/td>\n<td><span>Declarative, like SQL.<\/span>\n<p>Allows joining between any sized and distributed data set.<\/p><\/td>\n<td><span>Procedural with some declarative aspects (e.g. index selection).<\/span>\n<p>Can only join a sharded collection in an\u00a0<strong>unsharded collection.\u00a0<\/strong>To join two sharded collections, applications will have to write the join algorithm.<\/p><\/td>\n<\/tr>\n<tr>\n<td><b>JOINs supported<\/b><\/td>\n<td><span>LEFT OUTER JOIN<\/span>\n<p><span>INNER JOIN<\/span><\/p>\n<p><span>RIGHT OUTER JOIN<\/span><\/p><\/td>\n<td><span>$lookup implements the LEFT OUTER JOIN on scalar values.<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>ON-clause support<\/b><\/td>\n<td><span>Full expressions.<\/span>\n<p><span>Scalars<\/span><\/p>\n<p><span>Arrays<\/span><\/p><\/td>\n<td><span>Implicit equality<\/span>\n<p><span>Pipeline expression<\/span><\/p>\n<p><span>Arrays should to be $unwind before the $lookup<\/span><\/p><\/td>\n<\/tr>\n<tr>\n<td><b>JOIN implementation<\/b><\/td>\n<td><span>Block Nested Loop<\/span>\n<p><span>Hash join with user defined build and probes.<\/span><\/p><\/td>\n<td><span>Nested Loop<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>ON Clause<\/b><\/td>\n<td><span>ON clause with any expression.<\/span><\/td>\n<td><span>$pipeline expression<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>Array expressions in ON clause<\/b><\/td>\n<td><span>Use ANY, IN expressions.<\/span>\n<p><span>Supports UNNEST<\/span><\/p><\/td>\n<td><span>Pipeline with $unwind before $match<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>Explain<\/b><\/td>\n<td><span>Visual explain and <\/span>\n<p><span>JSON explain<\/span><\/p><\/td>\n<td><span>Visual explain and<\/span>\n<p><span>JSON explain<\/span><\/p><\/td>\n<\/tr>\n<tr>\n<td><b>JOIN order<\/b><\/td>\n<td><span>Left to right, as specified by the user. The optimizer is rule based.<\/span><\/td>\n<td><span>As specified in the pipeline.<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>Nested JOINs<\/b><\/td>\n<td><span>Supported via derived tables.<\/span>\n<p><span>FROM clause can have subselects which can have joins or subselects in turn.<\/span><\/p><\/td>\n<td><span>No<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>JOIN predicate processing<\/b><\/td>\n<td><span>Optimizer processes the join predicates, constant predicates and pushes the predicates to the index automatically.<\/span><\/td>\n<td><span>Manual design of predicates for each collection, careful ordering of pipeline stages without full help from the optimizer.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p>How about performance?\u00a0 Good question.\u00a0 That&#8217;s for a future blog!<\/p>\n\n\n\n<p><strong><span>And now, a quote:<\/span><\/strong><\/p>\n\n\n\n<p><span>\u201cA sentence should contain no unnecessary words, a paragraph no unnecessary sentences, for the same reason that a drawing should have no unnecessary lines and a machine no unnecessary parts.\u201d<\/span><\/p>\n\n\n\n<p><span> &#8212; William Strunk, Jr.\u00a0 <a href=\"https:\/\/www.amazon.com\/Elements-Style-William-Strunk-Jr\/dp\/194564401X\">Elements of Style<\/a>.<\/span><\/p>\n\n\n\n<p><strong>References:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Couchbase Documentation: <a href=\"https:\/\/docs.couchbase.com\">https:\/\/docs.couchbase.com<\/a><\/li>\n\n\n<li>MongoDB Documentation:\u00a0<a href=\"https:\/\/docs.mongodb.com\/\">https:\/\/docs.mongodb.com\/<\/a><\/li>\n\n\n<li>ANSI Joins in Couchbase N1QL:\u00a0<a href=\"https:\/\/www.couchbase.com\/blog\/ansi-join-support-n1ql\/\">https:\/\/www.couchbase.com\/blog\/ansi-join-support-n1ql\/<\/a><\/li>\n\n\n<li>N1QL Tutorial:\u00a0<a href=\"https:\/\/query-tutorial.couchbase.com\/tutorial\/#1\">https:\/\/query-tutorial.couchbase.com\/tutorial\/#1<\/a><\/li>\n\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>As NoSQL databases evolved, each added higher level APIs or languages to help programmers to complex things easily. SQL, having done that for relational data, showed the way. In SQL, developers say WHAT needs to be done and the database engine figures out the HOW. \u00a0HOW is the efficient procedure\/algorithm to execute the statement. Select, [&hellip;]<\/p>\n","protected":false},"author":55,"featured_media":1357,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[127,179,54,189,17,18],"tags":[44],"ppma_author":[291],"class_list":["post-1358","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-couchbase-architecture","category-couchbase-server","category-data-modeling","category-performance","category-n1ql-query","tag-mongodb"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Join JSON: Couchbase N1QL vs. MongoDB Query<\/title>\n<meta name=\"description\" content=\"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.\" \/>\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\/joining-json-comparing-couchbase-n1ql-mongodb\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Join JSON: Couchbase N1QL vs. MongoDB Query\" \/>\n<meta property=\"og:description\" content=\"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/joining-json-comparing-couchbase-n1ql-mongodb\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-07-12T06:07:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png\" \/>\n\t<meta property=\"og:image:width\" content=\"700\" \/>\n\t<meta property=\"og:image:height\" content=\"294\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/\"},\"author\":{\"name\":\"Keshav Murthy\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/c261644262bf98e146372fe647682636\"},\"headline\":\"How to Join JSON: Couchbase N1QL vs. MongoDB Query\",\"datePublished\":\"2018-07-12T06:07:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/\"},\"wordCount\":2182,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png\",\"keywords\":[\"mongodb\"],\"articleSection\":[\"Application Design\",\"Couchbase Architecture\",\"Couchbase Server\",\"Data Modeling\",\"High Performance\",\"SQL++ \\\/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/\",\"name\":\"How to Join JSON: Couchbase N1QL vs. MongoDB Query\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png\",\"datePublished\":\"2018-07-12T06:07:33+00:00\",\"description\":\"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png\",\"width\":700,\"height\":294},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/joining-json-comparing-couchbase-n1ql-mongodb\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Join JSON: Couchbase N1QL vs. MongoDB Query\"}]},{\"@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\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"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:\\\/\\\/secure.gravatar.com\\\/avatar\\\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g4e51d72fc07c662aa791316deafffac4\",\"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, and has received twenty four US patents.\",\"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":"How to Join JSON: Couchbase N1QL vs. MongoDB Query","description":"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.","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\/joining-json-comparing-couchbase-n1ql-mongodb\/","og_locale":"en_US","og_type":"article","og_title":"How to Join JSON: Couchbase N1QL vs. MongoDB Query","og_description":"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.","og_url":"https:\/\/www.couchbase.com\/blog\/joining-json-comparing-couchbase-n1ql-mongodb\/","og_site_name":"The Couchbase Blog","article_published_time":"2018-07-12T06:07:33+00:00","og_image":[{"width":700,"height":294,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png","type":"image\/png"}],"author":"Keshav Murthy","twitter_card":"summary_large_image","twitter_creator":"@rkeshavmurthy","twitter_misc":{"Written by":"Keshav Murthy","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/"},"author":{"name":"Keshav Murthy","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c261644262bf98e146372fe647682636"},"headline":"How to Join JSON: Couchbase N1QL vs. MongoDB Query","datePublished":"2018-07-12T06:07:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/"},"wordCount":2182,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png","keywords":["mongodb"],"articleSection":["Application Design","Couchbase Architecture","Couchbase Server","Data Modeling","High Performance","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/","url":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/","name":"How to Join JSON: Couchbase N1QL vs. MongoDB Query","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png","datePublished":"2018-07-12T06:07:33+00:00","description":"This article discusses how to join JSON documents while comparing Couchbase vs. MongoDB. Follow along as we review several real-world examples.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/Screen-Shot-2018-04-22-at-8.52.36-PM-e1531517244183.png","width":700,"height":294},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/ko\/joining-json-comparing-couchbase-n1ql-mongodb\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Join JSON: Couchbase N1QL vs. MongoDB Query"}]},{"@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\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","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:\/\/secure.gravatar.com\/avatar\/af74df754db27152971d0aed2f323ead5a1f9fe5afd0209af91e12e784451224?s=96&d=mm&r=g4e51d72fc07c662aa791316deafffac4","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, and has received twenty four US patents.","sameAs":["https:\/\/blog.planetnosql.com\/","https:\/\/x.com\/rkeshavmurthy"],"url":"https:\/\/www.couchbase.com\/blog\/author\/keshav-murthy\/"}]}},"acf":[],"authors":[{"term_id":291,"user_id":55,"is_guest":0,"slug":"keshav-murthy","display_name":"Keshav Murthy","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1358","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=1358"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1358\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/1357"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=1358"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=1358"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=1358"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1358"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}