December 10, 2014

Intro to Enterprise Cloud Storage, Part 2: How to Access a Cloudant Database

In the previous tutorial, I talked about how to create an account with Cloudant and from there create a database and new document. Now let's see how to access the database programmatically. In order to do so, you need a CouchDB driver for your particular language. In this example, I'll use node.js and the nano driver. But the concepts will carry over to any other language.

Remember that with Cloudant your documents are JSON objects. Because node.js uses JavaScript for its language, these documents can easily be copied between Cloudant and your node.js program. Let's first retrieve the document created last time. To do this, you'll need your Cloudant login information, your database name, and the document's _id field. The _id for the document in my database is the string 'd795ad9029793255261aba9fe045ac4f'. (Yours will be different; you can see it when you look at the document in the Cloudant web console. Its field name is _id.)

Here's an entire node.js app that retrieves the document and prints it out. You'll need to replace the login information, database name, and _id with your own. Note also that the username and password are the same that you use for logging into the Cloudant web console.

var nano = require('nano')({
    url: 'https://username:password@username.cloudant.com'
});
nano.use('linux_com_demo').get(
'd795ad9029793255261aba9fe045ac4f', function(err, doc) {
    console.log(doc);
});

(If you get an error message, "Cannot find module 'nano'", then make sure you installed nano with npm and that it's available in your node modules path.)

When you run this, you should see the full document appear in your console:

{ _id: 'd795ad9029793255261aba9fe045ac4f',
  _rev: '3-7b7ebadc7043829cb0499a6ed70a4b9a',
  first_name: 'George',
  last_name: 'Washington',
  lived: { born: 1732, died: 1799 },
  president: 1 }

This is pretty straightforward; the call to nano.use accesses the database, returning an object that lets you call get to retrieve the document.

You'll probably want to include some error handling. If your document isn't found, no exception will be thrown; instead, your document will be the "undefined" value. But you'll also get back a full set of error information in the first parameter of the callback function. I'll change the _id to something non-existent, and then print out the error message I get back. To do so, I'll change the callback function as follows:

if (err) {
    console.log(err);
    return;
}
console.log(doc);

Because of space limitations, I'm not going to show the full error object here. But err is an object with several members. Here's part of what I got back:

{
  name: 'Error',
  status_code: 404,
  'status-code': 404,
  error: 'not_found',
  reason: 'missing'
}

These members give a good description of what error occurred.

Uploading a document

Next, let's look at uploading a new document. This is where things get tricky, because CouchDB (and hence, Cloudant) uses revision numbers on documents, which I'll explain shortly.

First, uploading a document is easy. Here's a complete program that's separate from the previous:

var nano = require('nano')({
    url: 'https://username:
 This e-mail address is being protected from spambots. You need JavaScript enabled to view it
 '
});
var mydoc = {
    first_name: 'John',
    last_name: 'Adams',
    lived: { born: 1735, died: 1826 },
    president: 2
};
nano.use('linux_com_demo').insert(mydoc, function(err, doc) {
    if (err) {
        console.log(err);
        return;
    }
    console.log(doc);
});

When I run this, here's the response I see:

{ ok: true,
  id: 'b6fa8c64f64dbfdd40631b5ad7b922b2',
  rev: '1-e03edf9c7815a64cc1df4063d9a2fd6b' }

The id field in this response is the _id Cloudant assigned to the document, since we didn't provide one in the original object. (Note that in the response, the field is id without an underscore, but in the stored document, it's _id with an underscore.) We could have provided our own _id if we wanted to, instead of having Cloudant create one. In a real application, you'll want to take both the id and rev in this response and add them to your document as _id and _rev, respectively, if you plan to continue using them in your app.

Now let's hop on over to the web console and find the document. Log in, and click on the database name. You'll see its current list of documents, including the one created in the previous tutorial, and the new one, as shown in the following image.

cloudant doclist

However, this view only shows brief information about each document. Float the mouse over a document, and you'll see a little "Edit doc" button appear. Click it and you'll see the full doc, like so:

cloudant document

Document Revisions

Now let's talk about that field called _rev. This is the revision number of the document. If you try to write a document whose _id field already exists in the database, you need to also include the current revision number. Otherwise, the document will be rejected and you'll get back an error. The error message will be status code 409 and message "Document update conflict." The idea is pretty simple; when working on an existing document, just keep the _rev field around and use it to upload, and you'll be fine. When you save the document, you'll get back a new _rev field to use for the subsequent save.

But this has caused some headaches for people. If you have multiple people working on a document, and you want somebody to be able to override any other changes by other people that might have taken place in between retrieving and saving the document, then there's an easy workaround (albeit not very efficient): Read the document again as a temporary document; grab the temporary document's _rev field, copy it in the actual document, and then save. However, there's still the potential for a race condition in case another user saved the document in the middle of this process. Then you'll need to handle the error and try again. (But this is somewhat sloppy engineering; try to keep track of your _rev fields as much as possible.)

Conclusion

This has only been a brief look at how you can write code to access Cloudant. It's pretty easy to do so. There are more topics you can explore by reading the Cloudant documentation, such as how to create views, do full-text searches, and more. We can cover these in future tutorials.

Also, before I go, I want to mention that the coding aspects we've done in today's tutorial aren't unique to Cloudant. You can actually use these techniques for any CouchDB database, including one installed locally. That means you can test locally if you want. However, the search and index features of Cloudant are likely to not be present in your local installation. But the general features (creating, reading, updating, deleting, and views) will be. And once you start using Cloudant, you'll get the cloud replication features without having to manage your own servers. For small and medium sized businesses with limited resources, this can mean giving you time to focus on building your product, rather than maintaining database servers.

Click Here!