Wern Ancheta

Adventures in Web Development.

Getting Started With CouchDB in Node.js

| Comments

In this tutorial I’m going to walk you through how to get started with CouchDB in Node.js. But first here’s some background on what CouchDB is. CouchDB is a NoSQL database from the Apache Foundation. Just like any other NoSQL database out there. It uses JSON to store data and it deals with separate documents instead of tables and fields.

Installing CouchDB

You can install CouchDB by executing the following command:

1
sudo apt-get install couchdb

Once that’s done you can test if its successfully installed by accessing http://localhost:5984/ from your browser. You’re good to go if it returns a response similar to the following:

1
{"couchdb":"Welcome","uuid":"0eb12dd741b22a919c8701dd6dc14087","version":"1.5.0","vendor":{"version":"14.04","name":"Ubuntu"}}

Futon

If you’re from the RDBMS land. You might be familiar with Phpmyadmin. In CouchDB Futon is the equivalent of Phpmyadmin. It allows you to manage your CouchDB databases with ease. In case you’re wondering what Futon means, its basically a Japanese word. Futon is a traditional japanese bedding.

Ok enough with the trivia. You can access Futon by going to http://localhost:5984/_utils/. It should show you something similar to the following:

futon

The first thing you need to do is to configure futon so that it has an admin user. Because by default, every user who has access to it have admin privileges. It can only be accessed from the local computer so this isn’t really a security issue. Not unless a hacker gets to access the server. You can setup an admin by going into the configuration page. Just click ‘Configuration’ under the tools menu to get there. Next click on the ‘setup admin’ link found at the bottom right corner. This should open up a modal that asks you to enter the username and password that you can use for logging in as admin.

Just enter your desired username and password and then click ‘create’ to create the admin. You can now login as an admin by clicking on the ‘login’ link. Non-admin users will only now have read privileges once you have setup your first admin user.

With Futon you can create a new database, add documents, update documents, delete documents and delete a database. Using Futon is pretty straightforward so I’m just going to leave it to you to explore it.

Creating a Database

You can create a new database via Futon. From the Futon index page, click on the ‘create database’ link to create a new database. This will create a new database where you can add new documents.

Adding New Documents

You can add new documents by making a curl request to port 5984 of your localhost. Here’s an example:

1
curl -X POST http://127.0.0.1:5984/test_db/ -d '{"name": "Ash Ketchum", "age": 10, "type": "trainer"}' -H "Content-Type: application/json"

Here’s a breakdown of the options we have passed to curl:

  • -X POST http://127.0.0.1:5984/test/ – the -X option is used to specify the type of request and the host. In this case the host is the URL in which CouchDB is running. And the type of request is POST
  • -d '{"name": "Ash Ketchum", "age": 10, "type": "trainer"}'-d is used for specifying the data that you want to submit. In this case were using a JSON string to represent the data. Note that there are no fields that are required by CouchDB. But its helpful to specify a type field so that we can easily query documents later on based on their type.
  • -H "Content-Type: application/json"-H is used for specifying the header type.

Executing the command above will return something similar to the following:

1
2
3
4
5
{
    "ok":true,
    "id":"cc6b37f1e6b2215f2a5ccac38c000a43",
    "rev":"1-61280846062dcdb986c5a6c4aa9aaf03"
}

Usually this is the status of the request (ok), the id assigned to the document (id), and the revision number (rev).

Retrieving Documents

You can retrieve all documents from a specific database by using a GET request:

1
curl -X GET http://127.0.0.1:5984/test_db/_all_docs 

This returns the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "total_rows":1,
    "offset":0,
    "rows":[
        {
            "id":"cc6b37f1e6b2215f2a5ccac38c000a43",
            "key":"cc6b37f1e6b2215f2a5ccac38c000a43",
            "value":{
                "rev":"1-61280846062dcdb986c5a6c4aa9aaf03"
            }
        }
    ]
}

Note that this only returns the id, key and value of the document and not the actual contents of the documents. If you also need to return the contents, just add the include_docs as a query parameter and set its value to true:

1
curl -X GET http://127.0.0.1:5984/test_db/_all_docs?include_docs=true

If you want to retrieve a specific document, use the document id:

1
curl -X GET http://127.0.0.1:5984/test_db/cc6b37f1e6b2215f2a5ccac38c000a43

If you want to retrieve a specific revision, you can supply rev as a query parameter and then use the revision id as the value.

1
curl -X GET http://127.0.0.1:5984/test/cc6b37f1e6b2215f2a5ccac38c000a43?rev=1-61280846062dcdb986c5a6c4aa9aaf03

Updating Documents

You can update documents by using the document id and the revision id. All you have to do is make a PUT request to the database that you want to update and add the document id as a path. And then supply the updated data along with the revision that you want to update:

1
curl -X PUT http://127.0.0.1:5984/test_db/cc6b37f1e6b2215f2a5ccac38c000a43 -d '{"_rev": "1-61280846062dcdb986c5a6c4aa9aaf03", "name": "Ash Ketchum", "age": 12, "type": "trainer"}' -H "Content-Type: application/json"

It should return something similar to the following if the update was successful:

1
2
3
4
5
{
    "ok":true,
    "id":"cc6b37f1e6b2215f2a5ccac38c000a43",
    "rev":"2-0023f19d7d3097468a8eeec014018840"
}

Revisions is an important feature that comes with CouchDB. Its like a built-in version control for each document. You can always go back to a previous version of a specific document as long as you haven’t deleted it.

Deleting Documents

You can delete a document by using the same path as updating documents or when you’re retrieving them. The only difference is you need to use a DELETE request and supply the revision id as a query parameter:

1
curl -X DELETE http://127.0.0.1:5984/test_db/cc6b37f1e6b2215f2a5ccac38c000a43?rev=2-0023f19d7d3097468a8eeec014018840

This deletes the second revision of the document. If you check the document from Futon, you will no longer see it there. But you will still be able to get a specific revision which haven’t been deleted if you supply the previous revision id in the request for getting a specific document:

1
curl -X GET http://127.0.0.1:5984/test_db/cc6b37f1e6b2215f2a5ccac38c000a43?rev=1-61280846062dcdb986c5a6c4aa9aaf03

Backup and Restore

Unlike Phpmyadmin, Futon doesn’t come with backup and restore capabilities. Good thing we have this awesome guy who created a backup and restore utility for CouchDB. Just download the couchdb-backup.sh file from the Github repo and place it somewhere in your computer.

To backup a specific database, just use the bash command and supply the filename of the backup utility. You supply the -b option if you want to backup and -r if you want to restore. -H is the host, if you don’t supply the port it uses 5984 by default. -d is the name of the database. -f is the filename of the backup file that will be created. -u is the admin username that you use for logging in to Futon. And -p is the password:

1
bash couchdb-backup.sh -b -H 127.0.0.1 -d test_db -f test_db.json -u your_username -p your_password

To restore the backup, just supply the -r option instead of -b:

1
bash couchdb-backup.sh -r -H 127.0.0.1 -d test_db -f test_db.json -u your_username -p your_password

Views

Views are used to query the database for a specific data. If you’re coming from the RDBMS land, you usually select specific data using the SELECT command. And then you use WHERE to get what you want. Once you’re done, you call it a day. With CouchDB its different. Because it doesn’t come with functions that allows you to select specific data easily. In CouchDB we need to use views. A view is basically just a JavaScript function that emits the documents that you need.

Before we move on with working with views, you can add the following document to your CouchDB database if you want to follow along:

1
2
3
4
5
6
7
{"new_edits":false,"docs":[
{"_id":"cc6b37f1e6b2215f2a5ccac38c000e58","_rev":"1-cbc1dd4e0dd53b3f9770bb8edc30ae33","name":"pikachu","type":"electric","trainer":"ash","gender":"m"},
{"_id":"cc6b37f1e6b2215f2a5ccac38c001e2c","_rev":"2-fbe6131ea1248b83301900a5954dec6d","name":"squirtle","type":"water","trainer":"ash","gender":"m"},
{"_id":"cc6b37f1e6b2215f2a5ccac38c0020d9","_rev":"1-8f98424393470486d60cf5fff00f33d3","name":"starmie","type":"water","trainer":"misty","gender":"f"},
{"_id":"cc6b37f1e6b2215f2a5ccac38c00215e","_rev":"1-aac04234d60216760bd9e3f89fa602e9","name":"geodude","type":"rock","trainer":"brock","gender":"m"},
{"_id":"cc6b37f1e6b2215f2a5ccac38c0030b4","_rev":"1-280586eb35fc3bde31f88ec9913f3dcb","name":"onix","type":"rock","trainer":"brock","gender":"m"}
]}

What you see above is a backup file which you can restore by using the backup and restore utility which I introduced earlier.

Creating a View

You can create a view by selecting your database from Futon. From there, look for the view dropdown box and then select ‘temporary view…’. This allows you to test and create a view. Enter the following in the view code box:

1
2
3
function(doc) {
   emit(doc.type, null);
}

Click on ‘run’ to run it. This will list all of the documents in the database using the type field as its key. We have set the value to null because we don’t need it. The value can be set to doc and then the value that’s returned will be the actual contents of the document. You can do that but its not really good practice since it consumes a lot of memory. Once you see some output you can now click on ‘save as’ and then supply the name of the design document and the view name. You can name those with any name you want but its good practice to give the design document a name which represents the type of document. In this case its ‘pokemon’. And the view name would be the key that you use. Some folks usually prefix it with by_. I also prefer it so I’ll name the view ‘by_type’. Click on ‘save’ once you’re done giving the names.

Here’s how you can use the view:

1
curl "http://127.0.0.1:5984/test_db/_design/pokemon/_view/by_type?key=%22water%22"

Breaking it down, the first part of the URL is the host where CouchDB is running:

1
http://127.0.0.1:5984

Next is the database:

1
test_db

And then you specify the name of the design document by supplying _design followed by the name of the design document:

1
_design/pokemon

Next you also need to specify the view:

1
_view/by_type

And then lastly, your query:

1
key=%22water%22"

Note that you need to supply a URL encoded query. %22 represents double-quotes so were wrapping the actual query with %22 instead of double-quotes. Executing it would return the following. Basically the same as what you seen in Futon but this time its filtered according to the value you supplied as the key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "total_rows":5,
    "offset":3,
    "rows":[
        {
            "id":"cc6b37f1e6b2215f2a5ccac38c001e2c",
            "key":"water",
            "value":null
        },
        {
            "id":"cc6b37f1e6b2215f2a5ccac38c0020d9",
            "key":"water",
            "value":null
        }
    ]
}

So the idea of views is that you have to emit the value for the field that you want to perform your query on. In this case we have emitted the type field.

Working with Node.js

You can work with CouchDB using the Nano package. You can install it in your project by executing the following command:

1
npm install nano --save

To use nano, create a new JavaScript file and name it app.js. Then you can connect to CouchDB by adding the following code:

1
var nano = require('nano')('http://localhost:5984');

If you already have a specific database to work with, you can connect to it by using the db.use method and then supply the name of the database as the argument:

1
var test_db = nano.db.use('test_db');

Creating New Documents

You can create new documents by using the insert method:

1
2
3
4
5
6
7
8
9
10
11
var data = { 
    name: 'pikachu', 
    skills: ['thunder bolt', 'iron tail', 'quick attack', 'mega punch'], 
    type: 'electric' 
};

test_db.insert(data, 'unique_id', function(err, body){
  if(!err){
    //awesome
  }
});

The insert method takes up the data that you want to save as its first argument, the id as its second argument and the third is the function that will be called once it gets a response. Note that the id is optional, so you can choose to supply a value or not. If you didn’t supply a value for it then CouchDB will automatically generate a unique id for you.

Retrieving Documents

Views are still utilized when retrieving specific documents from CouchDB in Nano. The view method is used for specifying which view you want to use. This method takes the name of the design document as its first argument, the name of the view as its second and then the query parameters that you want to pass in as the third argument. The fourth argument is the function that you want to execute once a response has been received:

1
2
3
4
5
6
7
8
9
var type = 'water';
db.view('pokemon', 'by_type', {'key': type, 'include_docs': true}, function(err, body){
    
    if(!err){
        var rows = body.rows; //the rows returned
    }
    
    }
);

Updating Documents

Nano doesn’t come with an update method by default. That is why we need to define a custom method that would do it for us. Declare the following near the top of your app.js file, right after your database connection code.

1
2
3
4
5
6
7
test_db.update = function(obj, key, callback){
 var db = this;
 db.get(key, function (error, existing){ 
    if(!error) obj._rev = existing._rev;
    db.insert(obj, key, callback);
 });
}

You can then use the update method in your code:

1
2
3
4
5
6
db.update(doc, doc_id, function(err, res){
    if(!err){
        //document has been updated
    }

});

Note that you need the id of the document when performing an update. That’s why you first need to create a view that would emit a unique field as the key and the document id as the value. In this case the unique field is the name. Each Pokemon has a unique name so this works:

1
2
3
function(doc) {
   emit(doc.name, doc._id);
}

Just give this view a design name of ‘pokemon’ and a name of ‘by_name’. And then you can use this view to update a Pokemon by name. All you have to do is call the update method once you have retrieved the id and the current document.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var name = 'pikachu';
db.view('pokemon', 'by_name', {'key': name, 'include_docs': true}, function(select_err, select_body){
    if(!select_err){
        var doc_id = select_body.rows[0].id;
        var doc = select_body.rows[0].doc;
        
        //do your updates here
        doc.age = 99; //you can add new fields or update existing ones

        db.update(doc, doc_id, function(err, res){
            if(!err){
                //document has been updated
            }

        });        
    }
});

Deleting Documents

If you no longer want a specific document and you need to delete it, you can use the destroy method. This takes up the id of the document as the first argument, the revision id of the revision that you want to delete as the second argument, and then the function that you want to execute once you get a response:

1
2
3
4
5
test_db.destroy(doc_id, revision_id, function(err, body) {
    if(!err){
        //done deleting
    }
});

Conclusion

That’s it! In this tutorial you’ve learned about the basics of using CouchDB through Futon, Curl and Node.js. We have barely scratch the surface with this tutorial. Do check out the resources below if you want to learn more.

Resources

Comments