{"id":2918,"date":"2017-03-07T11:11:30","date_gmt":"2017-03-07T19:11:30","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=2918"},"modified":"2025-06-13T17:33:05","modified_gmt":"2025-06-14T00:33:05","slug":"migrate-mongodb-couchbase-n1ql","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/","title":{"rendered":"Migrate From MongoDB to Couchbase with N1QL"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Customers often tell us they\u2019re preparing to migrate from MongoDB to Couchbase. They come, in part, because they\u2019re tired of the problems they\u2019ve experienced learning how to query MongoDB. Couchbase with N1QL provides a better alternative, especially for scaling up modern applications.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Unfortunately, with MongoDB, migration options can be limited. One I wrote about recently involves moving<\/span> from <a href=\"https:\/\/www.couchbase.com\/blog\/migrating-mongodb-mongoose-restful-api-couchbase-ottoman\/\" target=\"_blank\" rel=\"noopener noreferrer\">MongoDB with Mongoose to Couchbase with Ottoman<\/a>. \u00a0The core of that tutorial was around using two different ODM tools in Node.js that shared the same APIs, making the transition almost seamless. \u00a0However, what if you&#8217;re not using an ODM in MongoDB and have no interest in using one?<\/p>\n<p>This time around we&#8217;re going to take a look at moving a Node.js application that uses MongoDB and the MongoDB query language to Couchbase with N1QL. \u00a0In short, N1QL is a technology that lets you run SQL queries against complex JSON data. \u00a0This makes it not only easy to use, but very clean in the application layer. \u00a0More information on N1QL can be found in the <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/4.6\/getting-started\/try-a-query.html\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase Developer Portal<\/a>.<\/p>\n<p><!--more--><\/p>\n<p>We&#8217;re going to be using the same example problem used in the <a href=\"https:\/\/www.couchbase.com\/blog\/migrating-mongodb-mongoose-restful-api-couchbase-ottoman\/\" target=\"_blank\" rel=\"noopener noreferrer\">previous article<\/a>, but it is alright if you haven&#8217;t seen it. \u00a0Everything here will be started with a clean slate.<\/p>\n<h2>The Requirements<\/h2>\n<p>There are a few requirements that must be met to make sure you are successful with this guide. \u00a0They can be seen as follows:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li><a href=\"https:\/\/www.mongodb.com\/download-center\" target=\"_blank\" rel=\"noopener noreferrer\">MongoDB<\/a> 3.4+<\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/downloads\/\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase<\/a> 4.5+<\/li>\n<li><a href=\"https:\/\/nodejs.org\/en\/\" target=\"_blank\" rel=\"noopener noreferrer\">Node.js<\/a> 6.0+<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Because we will be seeing both the MongoDB and Couchbase equivalent, you should have both databases available to you. \u00a0If you&#8217;re already a MongoDB developer, a lot may be familiar to you, but that is your call.<\/p>\n<h2>Understanding the NoSQL Data Model<\/h2>\n<p>Before developing the RESTful API with either technology, it is a good idea to first understand the data model that will be used.<\/p>\n<p>While both MongoDB and Couchbase are document databases, they are not entirely the same. \u00a0MongoDB stores data as BSON while Couchbase stores data as JSON. \u00a0From a modeling perspective, it won&#8217;t really matter to us.<\/p>\n<p>Take the data model for a school where you have students and you have courses. \u00a0For every course offered at the school, you might have a document that looks like the following:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \" title=\"NoSQL Model for Courses\">{\r\n    \"id\": \"course-1\",\r\n    \"type\": \"course\",\r\n    \"name\": \"Computer Science 101\",\r\n    \"term\": \"F2017\",\r\n    \"students\": [\r\n        \"student-1\",\r\n        \"student-2\"\r\n    ]\r\n}<\/pre>\n<p>Each course will maintain a list of all the students that have been registered. \u00a0In this case, the list will consist of id values that reference other documents. \u00a0We&#8217;re establishing our own document relationships.<\/p>\n<p>For every student at the school, they may have a NoSQL document that looks like the following:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \" title=\"NoSQL Model for Students\">{\r\n    \"id\": \"student-1\",\r\n    \"type\": \"student\",\r\n    \"firstname\": \"Nic\",\r\n    \"lastname\": \"Raboy\",\r\n    \"courses\": [\r\n        \"course-1\",\r\n        \"course-25\"\r\n    ]\r\n}<\/pre>\n<p>Notice that the above document is similar to how we modeled our courses. \u00a0Each student will maintain a list of all the courses that they are registered to. \u00a0These courses are ids that reference the appropriate course document.<\/p>\n<p>There are a hundred different ways we can model our documents, this is just one example. \u00a0For more information on data modeling, check out this <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/data-modeling\/intro-data-modeling.html\" target=\"_blank\" rel=\"noopener noreferrer\">documentation<\/a>.<\/p>\n<p>Now that we have a model for our documents, we can focus on building an API with each technology.<\/p>\n<h2>Developing an API with the MongoDB Query Language<\/h2>\n<p>While you might have your own MongoDB application code, we&#8217;re going to create one from scratch so the migration remains very easy to understand.<\/p>\n<p>Let&#8217;s start by creating a fresh project from our Command Prompt or Terminal:<\/p>\n<pre class=\"lang:sh decode:true\">npm init --y\r\nnpm install express body-parser mongodb --save<\/pre>\n<p>The above commands will create a new\u00a0<strong>package.json<\/strong> file in your current working directory and install the necessary framework and database dependencies.<\/p>\n<p>At the end of the day, we want our MongoDB project to have the following structure:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \">app.js\r\nroutes\/\r\n    courses.js\r\n    students.js\r\nmodels\/\r\n    student.js\r\n    course.js\r\npackage.json\r\nnode_modules\/<\/pre>\n<p>All interaction with the database will be done from each of the <strong>models<\/strong> and all API routing and interaction with the client will be done from the\u00a0<strong>routes<\/strong> files. \u00a0Bootstrapping the application and connecting to the database will be done from the\u00a0<strong>app.js<\/strong> file.<\/p>\n<h3>Creating a MongoDB Database Model within the Application<\/h3>\n<p>So let&#8217;s take a look at one of our database models. \u00a0Open the project&#8217;s\u00a0<strong>models\/course.js<\/strong> file and include the following code:<\/p>\n<pre class=\"lang:js decode:true\">var Database = require(\"..\/..\/app\").database;\r\nvar ObjectId = require(\"mongodb\").ObjectId;\r\n\r\nfunction CourseModel() { };\r\n\r\nCourseModel.save = function(data, callback) {\r\n    Database.collection(\"courses\").insertOne(data, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nCourseModel.updateStudents = function(id, students, callback) {\r\n    Database.collection(\"courses\").updateOne({ \"_id\": new ObjectId(id) },\r\n        {\r\n            $set: { \"students\": students }\r\n        }, function(error, result) {\r\n            if(error) {\r\n                return callback(error, null);\r\n            }\r\n            callback(null, result);\r\n        }\r\n    );\r\n}\r\n\r\nCourseModel.getById = function(documentId, callback) {\r\n    var cursor = Database.collection(\"courses\").aggregate([\r\n        { \"$match\": { \"_id\": new ObjectId(documentId) } },\r\n        { \"$unwind\": { \"path\": \"$students\", \"preserveNullAndEmptyArrays\": true } },\r\n        {\r\n            \"$lookup\": {\r\n                \"from\": \"students\",\r\n                \"localField\": \"students\",\r\n                \"foreignField\": \"_id\",\r\n                \"as\": \"studentObjects\"\r\n            }\r\n        },\r\n        { \"$unwind\": { \"path\": \"$studentObjects\", \"preserveNullAndEmptyArrays\": true} },\r\n        { \"$group\": {\r\n            \"_id\": {\r\n                \"_id\": \"$_id\",\r\n                \"name\": \"$name\"\r\n            },\r\n            \"students\": { \"$push\": \"$studentObjects\" }\r\n        }},\r\n        {\r\n            \"$project\": {\r\n                \"_id\": \"$_id._id\",\r\n                \"name\": \"$_id.name\",\r\n                \"students\": \"$students\"\r\n            }\r\n        },\r\n        { \"$limit\": 1 }\r\n    ]);\r\n    cursor.toArray(callback);\r\n};\r\n\r\nCourseModel.getAll = function(callback) {\r\n    var cursor = Database.collection(\"courses\").aggregate([\r\n        { \"$unwind\": { \"path\": \"$students\", \"preserveNullAndEmptyArrays\": true} },\r\n        {\r\n            \"$lookup\": {\r\n                \"from\": \"students\",\r\n                \"localField\": \"students\",\r\n                \"foreignField\": \"_id\",\r\n                \"as\": \"studentObjects\"\r\n            }\r\n        },\r\n        { \"$unwind\": { \"path\": \"$studentObjects\", \"preserveNullAndEmptyArrays\": true} },\r\n        { \"$group\": {\r\n            \"_id\": {\r\n                \"_id\": \"$_id\",\r\n                \"name\": \"$name\"\r\n            },\r\n            \"students\": { \"$push\": \"$studentObjects\" }\r\n        }},\r\n        {\r\n            \"$project\": {\r\n                \"_id\": \"$_id._id\",\r\n                \"name\": \"$_id.name\",\r\n                \"students\": \"$students\"\r\n            }\r\n        }\r\n    ]);\r\n    cursor.toArray(callback);\r\n};\r\n\r\nmodule.exports = CourseModel;<\/pre>\n<p>There is a lot happening in the above database model. \u00a0We need to break it down to make it easy to understand. \u00a0The more we understand, the easier the migration process to Couchbase will be.<\/p>\n<p>When we wish to save a document, we have the\u00a0<code>save<\/code> method:<\/p>\n<pre class=\"lang:js decode:true \">CourseModel.save = function(data, callback) {\r\n    Database.collection(\"courses\").insertOne(data, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n}<\/pre>\n<p>Using the open database we can insert a single document into the desired collection using the\u00a0<code>insertOne<\/code> function. \u00a0In this function we pass\u00a0<code>data<\/code> which can be a JavaScript object of any complexity that we wish to save. \u00a0Once saved, the result will be returned to the parent method that called it.<\/p>\n<p>Now what if we want to update a document that already exists? \u00a0In particular, what if we want to add a student to an already existing course?<\/p>\n<p>For this particular example, we can update the entire\u00a0<code>students<\/code> array that exists in the document:<\/p>\n<pre class=\"lang:js decode:true \">CourseModel.updateStudents = function(id, students, callback) {\r\n    Database.collection(\"courses\").updateOne({ \"_id\": new ObjectId(id) },\r\n        {\r\n            $set: { \"students\": students }\r\n        }, function(error, result) {\r\n            if(error) {\r\n                return callback(error, null);\r\n            }\r\n            callback(null, result);\r\n        }\r\n    );\r\n}<\/pre>\n<p>The above code will use the\u00a0<code>updateOne<\/code> method to lookup a particular document by id and replace the\u00a0<code>students<\/code> array with a new one that we provide via the\u00a0<code>updateStudents<\/code> function.<\/p>\n<p>Nothing too difficult so far and no real stress added to the developer.<\/p>\n<p>This is where things change. \u00a0When we save data we are saving an array of id values. \u00a0This is not data we want to see in query operations. \u00a0Instead we want to populate or expand these id values into their document equivalents:<\/p>\n<pre class=\"lang:js decode:true\">CourseModel.getAll = function(callback) {\r\n    var cursor = Database.collection(\"courses\").aggregate([\r\n        { \"$unwind\": { \"path\": \"$students\", \"preserveNullAndEmptyArrays\": true} },\r\n        {\r\n            \"$lookup\": {\r\n                \"from\": \"students\",\r\n                \"localField\": \"students\",\r\n                \"foreignField\": \"_id\",\r\n                \"as\": \"studentObjects\"\r\n            }\r\n        },\r\n        { \"$unwind\": { \"path\": \"$studentObjects\", \"preserveNullAndEmptyArrays\": true} },\r\n        { \"$group\": {\r\n            \"_id\": {\r\n                \"_id\": \"$_id\",\r\n                \"name\": \"$name\"\r\n            },\r\n            \"students\": { \"$push\": \"$studentObjects\" }\r\n        }},\r\n        {\r\n            \"$project\": {\r\n                \"_id\": \"$_id._id\",\r\n                \"name\": \"$_id.name\",\r\n                \"students\": \"$students\"\r\n            }\r\n        }\r\n    ]);\r\n    cursor.toArray(callback);\r\n};<\/pre>\n<p>To make this possible, the array must first be flattened via an\u00a0<code>$unwind<\/code> and joined via a\u00a0<code>$lookup<\/code> operation. \u00a0It doesn&#8217;t stop there because we want our results to be formatted in the same fashion, only replacing the ids for objects. \u00a0Because of this we have to do further flattening, grouping, and manipulations.<\/p>\n<p>A full explanation of joining data in MongoDB versus joining data in Couchbase can be seen in a <a href=\"https:\/\/www.couchbase.com\/blog\/joining-nosql-documents-mongodb-query-language-vs-couchbase-n1ql\/\" target=\"_blank\" rel=\"noopener noreferrer\">thorough article I wrote previously<\/a> on the subject.<\/p>\n<p>Long story short, the more complicated your data, the more complicated your aggregation query will be. \u00a0For a flexible data model, this becomes not very flexible for an application developer.<\/p>\n<p>Let&#8217;s take a quick look at our other model, the one that will manage student data. \u00a0Open the project&#8217;s\u00a0<strong>models\/student.js<\/strong> file and include the following JavaScript code:<\/p>\n<pre class=\"lang:js decode:true \">var Database = require(\"..\/..\/app\").database;\r\nvar ObjectId = require(\"mongodb\").ObjectId;\r\n\r\nfunction StudentModel() { };\r\n\r\nStudentModel.save = function(data, callback) {\r\n    Database.collection(\"students\").insertOne(data, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nStudentModel.updateCourses = function(id, courses, callback) {\r\n    Database.collection(\"students\").updateOne({ \"_id\": new ObjectId(id) },\r\n        {\r\n            $set: { \"courses\": courses }\r\n        }, function(error, result) {\r\n            if(error) {\r\n                return callback(error, null);\r\n            }\r\n            callback(null, result);\r\n        }\r\n    );\r\n}\r\n\r\nStudentModel.getById = function(documentId, callback) {\r\n    var cursor = Database.collection(\"students\").aggregate([\r\n        { \"$match\": { \"_id\": new ObjectId(documentId) } },\r\n        { \"$unwind\": { \"path\": \"$courses\", \"preserveNullAndEmptyArrays\": true } },\r\n        {\r\n            \"$lookup\": {\r\n                \"from\": \"courses\",\r\n                \"localField\": \"courses\",\r\n                \"foreignField\": \"_id\",\r\n                \"as\": \"courseObjects\"\r\n            }\r\n        },\r\n        { \"$unwind\": { \"path\": \"$courseObjects\", \"preserveNullAndEmptyArrays\": true } },\r\n        { \"$group\": {\r\n            \"_id\": {\r\n                \"_id\": \"$_id\",\r\n                \"name\": \"$name\"\r\n            },\r\n            \"courses\": { \"$push\": \"$courseObjects\" }\r\n        }},\r\n        {\r\n            \"$project\": {\r\n                \"_id\": \"$_id._id\",\r\n                \"name\": \"$_id.name\",\r\n                \"courses\": \"$courses\"\r\n            }\r\n        },\r\n        { \"$limit\": 1 }\r\n    ]);\r\n    cursor.toArray(callback);\r\n};\r\n\r\nStudentModel.getAll = function(callback) {\r\n    var cursor = Database.collection(\"students\").aggregate([\r\n        { \"$unwind\": { \"path\": \"$courses\", \"preserveNullAndEmptyArrays\": true } },\r\n        {\r\n            \"$lookup\": {\r\n                \"from\": \"courses\",\r\n                \"localField\": \"courses\",\r\n                \"foreignField\": \"_id\",\r\n                \"as\": \"courseObjects\"\r\n            }\r\n        },\r\n        { \"$unwind\": { \"path\": \"$courseObjects\", \"preserveNullAndEmptyArrays\": true } },\r\n        { \"$group\": {\r\n            \"_id\": {\r\n                \"_id\": \"$_id\",\r\n                \"firstname\": \"$firstname\",\r\n                \"lastname\": \"$lastname\",\r\n                \"address\": \"$address\"\r\n            },\r\n            \"courses\": { \"$push\": \"$courseObjects\" }\r\n        }},\r\n        {\r\n            \"$project\": {\r\n                \"_id\": \"$_id._id\",\r\n                \"firstname\": \"$_id.firstname\",\r\n                \"lastname\": \"$_id.lastname\",\r\n                \"address\": \"$_id.address\",\r\n                \"courses\": \"$courses\"\r\n            }\r\n        }\r\n    ]);\r\n    cursor.toArray(callback);\r\n};\r\n\r\nmodule.exports = StudentModel;<\/pre>\n<p>Pretty much the same rules apply to the above model versus the model we saw representing course data. \u00a0This is because the two document models were very similar to begin with. \u00a0Flat for the most part with an array of id values.<\/p>\n<p>This brings us to the API endpoints that make use of these database methods.<\/p>\n<h3>Creating the RESTful API Routes for the Application<\/h3>\n<p>This is the easy part, and actually the most consistent between the two database technologies because it isn&#8217;t database dependent.<\/p>\n<p>Let&#8217;s have a look at the project&#8217;s\u00a0<strong>routes\/courses.js<\/strong> file:<\/p>\n<pre class=\"lang:js decode:true \">var CourseModel = require(\"..\/models\/course\");\r\n\r\nvar router = function(app) {\r\n\r\n    app.get(\"\/courses\", function(request, response) {\r\n        CourseModel.getAll(function(error, result) {\r\n            if(error) {\r\n                return response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(result);\r\n        });\r\n    });\r\n\r\n    app.get(\"\/course\/:id\", function(request, response) {\r\n        CourseModel.getById(request.params.id, function(error, result) {\r\n            if(error) {\r\n                return response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(result[0]);\r\n        });\r\n    });\r\n\r\n    app.post(\"\/courses\", function(request, response) {\r\n        if(!request.body.name) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"A `name` is required\"});\r\n        }\r\n        CourseModel.save(request.body, function(error, course) {\r\n            if(error) {\r\n                return response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(course);\r\n        });\r\n    });\r\n\r\n}\r\n\r\nmodule.exports = router;<\/pre>\n<p>In the above code we have three API routes. \u00a0From an external client we&#8217;ll be able to list all courses, find a particular course, or save a new course.<\/p>\n<p>Depending on which endpoint is hit, the appropriate database model function will run. \u00a0Not much heavy lifting is done in the routes, which based on their name, are only meant for routing.<\/p>\n<p>The other routing file is going to be a bit different. \u00a0Open the project&#8217;s\u00a0<strong>routes\/students.js<\/strong> file and include the following JavaScript code:<\/p>\n<pre class=\"lang:js decode:true \">var StudentModel = require(\"..\/models\/student\");\r\nvar CourseModel = require(\"..\/models\/course\");\r\n\r\nvar router = function(app) {\r\n\r\n    app.get(\"\/students\", function(request, response) {\r\n        StudentModel.getAll(function(error, result) {\r\n            if(error) {\r\n                response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(result);\r\n        });\r\n    });\r\n\r\n    app.get(\"\/student\/:id\", function(request, response) {\r\n        StudentModel.getById(request.params.id, function(error, result) {\r\n            if(error) {\r\n                response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(result);\r\n        });\r\n    });\r\n\r\n    app.post(\"\/students\", function(request, response) {\r\n        if(!request.body.firstname) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"A `firstname` is required\"});\r\n        } else if(!request.body.lastname) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"A `lastname` is required\"});\r\n        } else if(!request.body.address) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"An `address` is required\"});\r\n        }\r\n        StudentModel.save(request.body, function(error, student) {\r\n            if(error) {\r\n                return response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            response.send(student);\r\n        });\r\n    });\r\n\r\n    app.post(\"\/student\/course\", function(request, response) {\r\n        if(!request.body.student_id) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"A `student_id` is required\" });\r\n        } else if(!request.body.course_id) {\r\n            return response.status(401).send({ \"success\": false, \"message\": \"A `course_id` is required\" });\r\n        }\r\n        CourseModel.getById(request.body.course_id, function(error, course) {\r\n            if(error) {\r\n                return response.status(401).send({ \"success\": false, \"message\": error});\r\n            }\r\n            StudentModel.getById(request.body.student_id, function(error, student) {\r\n                if(error) {\r\n                    return response.status(401).send({ \"success\": false, \"message\": error});\r\n                }\r\n                if(course != null &amp;&amp; student != null) {\r\n                    if(!student[0].courses) {\r\n                        student[0].courses = [];\r\n                    }\r\n                    if(!course[0].students) {\r\n                        course[0].students = [];\r\n                    }\r\n                    var courses = [];\r\n                    var students = [];\r\n                    for(var i = 0; i &lt; student[0].courses.length; i++) {\r\n                        courses.push(student[0].courses[i]._id);\r\n                    }\r\n                    for(var i = 0; i &lt; course[0].students.length; i++) {\r\n                        students.push(course[0].students[i]._id);\r\n                    }\r\n                    courses.push(course[0]._id);\r\n                    students.push(student[0]._id);\r\n                    StudentModel.updateCourses(student[0]._id, courses, function(error, result) {});\r\n                    CourseModel.updateStudents(course[0]._id, students, function(error, result) {});\r\n                    response.send(student[0]);\r\n                } else {\r\n                    return response.status(401).send({ \"success\": false, \"message\": \"The `student_id` or `course_id` was invalid\"});\r\n                }\r\n            });\r\n        });\r\n    });\r\n\r\n}\r\n\r\nmodule.exports = router;<\/pre>\n<p>Like with the other route, there is a lot going on, but most of that is near identical. \u00a0Where are differences are falls in the\u00a0<code>\/student\/course<\/code> endpoint that is responsible for adding courses to a student and students to a course.<\/p>\n<p>When hitting this endpoint we first get the student and course information based on the passed id value. \u00a0They both need to exist, otherwise we&#8217;ll throw an error. \u00a0If they both exist, we&#8217;ll push the student id into the\u00a0<code>students<\/code> array for the course document and the course id into the\u00a0<code>courses<\/code> array of the student document. \u00a0Then we&#8217;ll call our update method and return a result to the end user.<\/p>\n<h3>Bringing it Together and Bootstrapping the Application<\/h3>\n<p>The API is ready to go at this point. \u00a0We just need to bootstrap the Node.js application and connect to the database. \u00a0This is the easy part.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>app.js<\/strong> file and include the following code:<\/p>\n<pre class=\"lang:js decode:true \">var MongoClient = require(\"mongodb\").MongoClient;\r\nvar Express = require(\"express\");\r\nvar BodyParser = require(\"body-parser\");\r\n\r\nvar app = Express();\r\napp.use(BodyParser.json());\r\n\r\nMongoClient.connect(\"mongodb:\/\/localhost:27017\/example\", function(error, database) {\r\n    if(error) {\r\n        return console.log(\"Could not establish a connection to MongoDB\");\r\n    }\r\n    module.exports.database = database;\r\n    var studentRoutes = require(\".\/mongodb\/routes\/students\")(app);\r\n    var courseRoutes = require(\".\/mongodb\/routes\/courses\")(app);\r\n    var server = app.listen(3000, function() {\r\n        console.log(\"Connected on port 3000...\");\r\n    });\r\n});<\/pre>\n<p>In the above code we are importing each of the dependencies that we downloaded and initializing Express Framework. \u00a0Before we start serving the API, we need to establish a connection to MongoDB. \u00a0Once the connection is established, the routes are connected and the application starts serving.<\/p>\n<p>At this point the RESTful API can be reached at https:\/\/localhost:3000 and tested with popular tools like <a href=\"https:\/\/www.thepolyglotdeveloper.com\/2015\/01\/using-postman-troubleshoot-restful-api-requests\/\" target=\"_blank\" rel=\"noopener noreferrer\">Postman<\/a> or Fiddler.<\/p>\n<h2>Developing an API with Couchbase and N1QL<\/h2>\n<p>So we have an example to work with when it comes to MongoDB and Node.js. \u00a0That example used the MongoDB query language when communicating with the database.<\/p>\n<p>Now we&#8217;re going to take that application and move it to <a href=\"https:\/\/www.couchbase.com\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase<\/a>. \u00a0We&#8217;re doing this because not only does Couchbase scale better and have better performance, the query language is far simpler and easier to maintain within an application.<\/p>\n<p>Like with the MongoDB application, we&#8217;re going to start from scratch, even though much of what we see will be identical. \u00a0From the Command Prompt or Terminal, execute the following:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">npm init --y\r\nnpm install express body-parser couchbase --save<\/pre>\n<p>The above commands should look familiar. \u00a0We&#8217;re creating a\u00a0<strong>package.json<\/strong> file and installing our dependencies, but instead of MongoDB we&#8217;re using Couchbase.<\/p>\n<p>The project will hold the same structure as seen in the previous project. \u00a0It should look like this:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \">app.js\r\nroutes\/\r\n    courses.js\r\n    students.js\r\nmodels\/\r\n    course.js\r\n    student.js\r\npackage.json\r\nnode_modules\/<\/pre>\n<p>The same logic as seen previously will end up in each of these files. \u00a0The difference being the syntax for Couchbase.<\/p>\n<h3>Creating a Couchbase Database Model within the Application<\/h3>\n<p>Starting with the same order, we&#8217;re going to create our database model functions. \u00a0As mentioned earlier, we&#8217;re going to be using N1QL which is an extreme highlight of Couchbase because it allows you to write SQL queries. \u00a0These queries are executed on the database and not within your Node.js application.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>models\/course.js<\/strong> file and include the following code:<\/p>\n<pre class=\"lang:js decode:true \">var Uuid = require(\"uuid\");\r\nvar Bucket = require(\"..\/..\/app\").bucket;\r\nvar N1qlQuery = require(\"couchbase\").N1qlQuery;\r\n\r\nfunction CourseModel() { };\r\n\r\nCourseModel.save = function(data, callback) {\r\n    data.id = Uuid.v4();\r\n    data.type = \"course\";\r\n    data.students = [];\r\n    var statement = \"INSERT INTO `\" + Bucket._name + \"` (KEY, VALUE) VALUES ($1, $2) RETURNING `\" + Bucket._name + \"`.*\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [data.id, data], function(error, result) {\r\n        if(error) {\r\n            callback(error, null);\r\n            return;\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nCourseModel.updateStudents = function(id, courses, callback) {\r\n    var statement = \"UPDATE `\" + Bucket._name + \"` USE KEYS $1 SET students = $2 RETURNING `\" + Bucket._name + \"`.*\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [id, courses], function(error, result) {\r\n        if(error) {\r\n            callback(error, null);\r\n            return;\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nCourseModel.getById = function(documentId, callback) {\r\n    var statement = \"SELECT s.id, s.type, s.name, \" +\r\n                    \"(SELECT t.* FROM `\" + Bucket._name + \"` AS t USE KEYS s.students) AS students \" +\r\n                    \"FROM `\" + Bucket._name + \"` AS s \" +\r\n                    \"WHERE s.type = 'course' AND s.id = $1\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [documentId], function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n};\r\n\r\nCourseModel.getAll = function(callback) {\r\n    var statement = \"SELECT s.id, s.type, s.name, \" +\r\n                    \"(SELECT t.* FROM `\" + Bucket._name + \"` AS t USE KEYS s.students) AS students \" +\r\n                    \"FROM `\" + Bucket._name + \"` AS s \" +\r\n                    \"WHERE s.type = 'course'\";\r\n    var query = N1qlQuery.fromString(statement).consistency(N1qlQuery.Consistency.REQUEST_PLUS);\r\n    Bucket.query(query, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n};\r\n\r\nmodule.exports = CourseModel;<\/pre>\n<p>In the above code we have the same set of database related functions that we saw in the MongoDB example. \u00a0Inside each of these functions are N1QL queries. \u00a0Not just N1QL queries, but parameterized N1QL queries to help fight off SQL injection attacks.<\/p>\n<p>Take a look at the\u00a0<code>getAll<\/code> method that was previously super complicated in the MongoDB version:<\/p>\n<pre class=\"lang:js decode:true \">CourseModel.getAll = function(callback) {\r\n    var statement = \"SELECT s.id, s.type, s.name, \" +\r\n                    \"(SELECT t.* FROM `\" + Bucket._name + \"` AS t USE KEYS s.students) AS students \" +\r\n                    \"FROM `\" + Bucket._name + \"` AS s \" +\r\n                    \"WHERE s.type = 'course'\";\r\n    var query = N1qlQuery.fromString(statement).consistency(N1qlQuery.Consistency.REQUEST_PLUS);\r\n    Bucket.query(query, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n};<\/pre>\n<p>This time around we have a simple query that includes a subquery. \u00a0Should our data needs become more complex, the query can be altered without gaining significant size or complexity.<\/p>\n<p>So let&#8217;s look at our other database model. \u00a0Open the project&#8217;s\u00a0<strong>models\/student.js<\/strong> file and include the following JavaScript code:<\/p>\n<pre class=\"lang:js decode:true \">var Uuid = require(\"uuid\");\r\nvar Bucket = require(\"..\/..\/app\").bucket;\r\nvar N1qlQuery = require(\"couchbase\").N1qlQuery;\r\n\r\nfunction StudentModel() { };\r\n\r\nStudentModel.save = function(data, callback) {\r\n    data.id = Uuid.v4();\r\n    data.type = \"student\";\r\n    data.courses = [];\r\n    var statement = \"INSERT INTO `\" + Bucket._name + \"` (KEY, VALUE) VALUES ($1, $2) RETURNING `\" + Bucket._name + \"`.*\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [data.id, data], function(error, result) {\r\n        if(error) {\r\n            callback(error, null);\r\n            return;\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nStudentModel.updateCourses = function(id, courses, callback) {\r\n    var statement = \"UPDATE `\" + Bucket._name + \"` USE KEYS $1 SET courses = $2 RETURNING `\" + Bucket._name + \"`.*\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [id, courses], function(error, result) {\r\n        if(error) {\r\n            callback(error, null);\r\n            return;\r\n        }\r\n        callback(null, result);\r\n    });\r\n}\r\n\r\nStudentModel.getById = function(documentId, callback) {\r\n    var statement = \"SELECT t.id, t.type, t.firstname, t.lastname, t.address, \" +\r\n                    \"(SELECT s.* FROM `\" + Bucket._name + \"` AS s USE KEYS t.courses) AS courses \" +\r\n                    \"FROM `\" + Bucket._name + \"` AS t \" +\r\n                    \"WHERE t.type = 'student' AND t.id = $1\";\r\n    var query = N1qlQuery.fromString(statement);\r\n    Bucket.query(query, [documentId], function(error, result) {\r\n        if(error) {\r\n            console.log(error);\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n};\r\n\r\nStudentModel.getAll = function(callback) {\r\n    var statement = \"SELECT t.id, t.type, t.firstname, t.lastname, t.address, \" +\r\n                    \"(SELECT s.* FROM `\" + Bucket._name + \"` AS s USE KEYS t.courses) AS courses \" +\r\n                    \"FROM `\" + Bucket._name + \"` AS t \" +\r\n                    \"WHERE t.type = 'student'\";\r\n    var query = N1qlQuery.fromString(statement).consistency(N1qlQuery.Consistency.REQUEST_PLUS);\r\n    Bucket.query(query, function(error, result) {\r\n        if(error) {\r\n            return callback(error, null);\r\n        }\r\n        callback(null, result);\r\n    });\r\n};\r\n\r\nmodule.exports = StudentModel;<\/pre>\n<p>Look familiar? \u00a0The two database models are similar because the two document models are similar. \u00a0Again, should the complexity change, the application layer will still be easy to manage with N1QL queries.<\/p>\n<p>Because the API routes don&#8217;t have any dependencies on the database, the code between the MongoDB application and the Couchbase application can be shared. \u00a0To be clear, I&#8217;m referring to the files found in the\u00a0<strong>routes<\/strong> directory.<\/p>\n<h3>Bootstrapping the Application and Connecting to Couchbase<\/h3>\n<p>With the endpoints in place and the database models communicating to Couchbase through N1QL, we can finish off the application.<\/p>\n<p>Open the project&#8217;s\u00a0<strong>app.js<\/strong> file and include the following JavaScript code:<\/p>\n<pre class=\"lang:js decode:true \">var Couchbase = require(\"couchbase\");\r\nvar Express = require(\"express\");\r\nvar BodyParser = require(\"body-parser\");\r\n\r\nvar app = Express();\r\napp.use(BodyParser.json());\r\n\r\nmodule.exports.bucket = (new Couchbase.Cluster(\"couchbase:\/\/localhost\")).openBucket(\"example\");\r\nvar studentRoutes = require(\".\/couchbase\/routes\/students\")(app);\r\nvar courseRoutes = require(\".\/couchbase\/routes\/courses\")(app);\r\nvar server = app.listen(3000, function() {\r\n    console.log(\"Connected on port 3000...\");\r\n});<\/pre>\n<p>In the above code we are importing the dependencies that we had installed and initializing Express Framework. \u00a0Then we are establishing a connection to the database, bringing our routes together, and starting the Node.js server.<\/p>\n<p>Because we are using N1QL, don&#8217;t forget to create at least one index on your Couchbase Bucket. \u00a0It can be as simple as the following:<\/p>\n<pre class=\"lang:default highlight:0 decode:true \">CREATE PRIMARY INDEX ON `example`;<\/pre>\n<p>At this point you should be able to access your application in the same fashion as MongoDB. \u00a0Visit https:\/\/localhost:3000 from your web browser or with a tool like Postman or Fiddler.<\/p>\n<h2>Conclusion<\/h2>\n<p>You just saw how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead. \u00a0This is an alternative to the <a href=\"https:\/\/www.couchbase.com\/blog\/migrating-mongodb-mongoose-restful-api-couchbase-ottoman\/\" target=\"_blank\" rel=\"noopener noreferrer\">Mongoose to Ottoman ODM<\/a> solution that I wrote about previously.<\/p>\n<p>So why would you want to switch from MongoDB to Couchbase? \u00a0Well Couchbase is a lot faster and easier to scale, but N1QL is also incredibly simple when working with complex data. \u00a0You&#8217;ll be able to reduce your code drastically and keep it more maintainable. \u00a0Check out the Couchbase vs. MongoDB query <a href=\"https:\/\/www.couchbase.com\/blog\/joining-nosql-documents-mongodb-query-language-vs-couchbase-n1ql\/\" target=\"_blank\" rel=\"noopener noreferrer\">tutorial<\/a> I wrote about in terms of joining data between the two databases.<\/p>\n<p>For more information on how to use Couchbase in a Node.js application:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>Check out the <a href=\"https:\/\/developer.couchbase.com\" target=\"_blank\" rel=\"noopener noreferrer\">Couchbase Developer Portal<\/a>.<\/li>\n<li>Try one of the <a href=\"https:\/\/docs.couchbase.com\/server\/current\/develop\/integrations.html#ide-integrations\">Couchbase developer IDEs\u2014JetBrains, VSCode<\/a>\u2014that we have plugins for.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Customers often tell us they\u2019re preparing to migrate from MongoDB to Couchbase. They come, in part, because they\u2019re tired of the problems they\u2019ve experienced learning how to query MongoDB. Couchbase with N1QL provides a better alternative, especially for scaling up [&hellip;]<\/p>\n","protected":false},"author":63,"featured_media":2787,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,1822,1812],"tags":[1393,1309,1745],"ppma_author":[9032],"class_list":["post-2918","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-node-js","category-n1ql-query","tag-api","tag-mongodb","tag-restful"],"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>Migrate From MongoDB to Couchbase with N1QL - The Couchbase Blog<\/title>\n<meta name=\"description\" content=\"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.\" \/>\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\/migrate-mongodb-couchbase-n1ql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Migrate From MongoDB to Couchbase with N1QL\" \/>\n<meta property=\"og:description\" content=\"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/thepolyglotdeveloper\" \/>\n<meta property=\"article:published_time\" content=\"2017-03-07T19:11:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T00:33:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"389\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@nraboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nic Raboy, Developer Advocate, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\"},\"author\":{\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1\"},\"headline\":\"Migrate From MongoDB to Couchbase with N1QL\",\"datePublished\":\"2017-03-07T19:11:30+00:00\",\"dateModified\":\"2025-06-14T00:33:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\"},\"wordCount\":2176,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png\",\"keywords\":[\"API\",\"mongodb\",\"restful\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"Node.js\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\",\"name\":\"Migrate From MongoDB to Couchbase with N1QL - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png\",\"datePublished\":\"2017-03-07T19:11:30+00:00\",\"dateModified\":\"2025-06-14T00:33:05+00:00\",\"description\":\"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png\",\"width\":1100,\"height\":389},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Migrate From MongoDB to Couchbase with N1QL\"}]},{\"@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\/bb545ebe83bb2d12f91095811d0a72e1\",\"name\":\"Nic Raboy, Developer Advocate, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g\",\"caption\":\"Nic Raboy, Developer Advocate, Couchbase\"},\"description\":\"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.\",\"sameAs\":[\"https:\/\/www.thepolyglotdeveloper.com\",\"https:\/\/www.facebook.com\/thepolyglotdeveloper\",\"https:\/\/x.com\/nraboy\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/nic-raboy-2\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Migrate From MongoDB to Couchbase with N1QL - The Couchbase Blog","description":"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.","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\/migrate-mongodb-couchbase-n1ql\/","og_locale":"en_US","og_type":"article","og_title":"Migrate From MongoDB to Couchbase with N1QL","og_description":"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.","og_url":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/","og_site_name":"The Couchbase Blog","article_author":"https:\/\/www.facebook.com\/thepolyglotdeveloper","article_published_time":"2017-03-07T19:11:30+00:00","article_modified_time":"2025-06-14T00:33:05+00:00","og_image":[{"width":1100,"height":389,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png","type":"image\/png"}],"author":"Nic Raboy, Developer Advocate, Couchbase","twitter_card":"summary_large_image","twitter_creator":"@nraboy","twitter_misc":{"Written by":"Nic Raboy, Developer Advocate, Couchbase","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/"},"author":{"name":"Nic Raboy, Developer Advocate, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/bb545ebe83bb2d12f91095811d0a72e1"},"headline":"Migrate From MongoDB to Couchbase with N1QL","datePublished":"2017-03-07T19:11:30+00:00","dateModified":"2025-06-14T00:33:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/"},"wordCount":2176,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png","keywords":["API","mongodb","restful"],"articleSection":["Best Practices and Tutorials","Couchbase Server","Node.js","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/","url":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/","name":"Migrate From MongoDB to Couchbase with N1QL - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png","datePublished":"2017-03-07T19:11:30+00:00","dateModified":"2025-06-14T00:33:05+00:00","description":"Learn how to take a Node.js application that uses MongoDB and the MongoDB Query Language and convert it to Couchbase with N1QL instead.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/02\/mongo-to-couchbase.png","width":1100,"height":389},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/migrate-mongodb-couchbase-n1ql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Migrate From MongoDB to Couchbase with N1QL"}]},{"@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\/bb545ebe83bb2d12f91095811d0a72e1","name":"Nic Raboy, Developer Advocate, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/8863514d8bed0cf6080f23db40e00354","url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","caption":"Nic Raboy, Developer Advocate, Couchbase"},"description":"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.","sameAs":["https:\/\/www.thepolyglotdeveloper.com","https:\/\/www.facebook.com\/thepolyglotdeveloper","https:\/\/x.com\/nraboy"],"url":"https:\/\/www.couchbase.com\/blog\/author\/nic-raboy-2\/"}]}},"authors":[{"term_id":9032,"user_id":63,"is_guest":0,"slug":"nic-raboy-2","display_name":"Nic Raboy, Developer Advocate, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bedeb68368d4681aca4c74fe5f697f0c423b80d498ec50fd915ba018b72c101f?s=96&d=mm&r=g","author_category":"","last_name":"Raboy","first_name":"Nic","job_title":"","user_url":"https:\/\/www.thepolyglotdeveloper.com","description":"Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2918","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\/63"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=2918"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/2918\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/2787"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=2918"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=2918"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=2918"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=2918"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}