Elvenware

Table of Contents

CouchDb

CouchDb is NoSQL database. This means that you do not use SQL to query it. It uses key/value pairs rather than structured relational data.

This is nothing fundamentally different about the internal structure of SQL database and a NoSQL. Underneath, they both consist of B-Trees or similar data structures and a series of indexes. The difference is not in the internals, but in the way that you access the data. In many cases, the data itself is structured differently.

CouchDb is based on JSON. Instead of using structured data with clearly defined sizes for each bit of data that you store, CouchDb simply accepts JSON.

You can, and will define indexes on your JSON data. You can also set up filters so that it is impossible to insert records that do not support a particular structure. For instance, you can set up filters that ensure that you cannot insert a record that does not contain a first name field, etc. You can define pretty much any kind of filter you want.

You can, and will use CouchDb to define one to many and many to many relationships. It is just that you use a different syntax than you would use in a relational database. Creating a unique constraint is more difficult in CouchDb.

One key difference between NoSQL and SQL database can be summed up with the word "relaxed." In CouchDb, you can avoid many of the strictures built into SQL databases. You don't have to obey the strict rules that are built into SQL databases. Sometimes, however, the rules in a relational database are useful. It is a question of finding the right tool for the right job.

CouchDb is distributed databases. This means that it is very good at scaling up to handle huge quantities of data by simply adding more machines to your database. CouchDb can transparently handle scaling out your database across multiple machines, or you can define specifically how it should distribute your data. In most cases, the choice is up to you.

In general, use relational databases if you:

On the other hand, use NoSQL if you:

This does not mean that you can't use NoSQL data to work with highly structured data, and vice versa. These are simply general guidelines.

Install

There is a Windows and Linux install process. Each has its own quirks, but neither is difficult.

CouchDb for Windows

http://apache.mirrors.pair.com/couchdb/binary/win/1.3.0/setup-couchdb-1.3.0_R15B03-1.exe

CouchDb will probably be installed here:

C:Files (x86)C:Files (x86)Software Foundation

CouchDb runs as a service, so use the Services panel to stop and start it. You can control Windows services via the control panel:

Control Panel\System and Security\Administrative Tools

The configuration file is likely stored here:

C:\Program Files (x86)\Apache\CouchDB\etc\couchdb\default.ini
C:\Program Files (x86)\Apache\CouchDB\etc\couchdb\local.ini

Apparently default.ini can be overwritten during an upgrade or install, so you might want to edit local.ini.

For details, see this, which describes a hierarchy of configuration files:

<http://docs.couchdb.org/en/latest/configuring.html>

Ultimately, you will probably have to know how to edit these files, as your IP address will change as you log into various wireless networks. Be sure to see up an Admin Account!

CouchDb for Linux

For the Linux install:

sudo apt-get install couchdb -y

After the install you will probably want to start working off your server's IP, rather than off local host. This is especially true if you are running Linux on AWS, or running a "headless" (non-GUI) based installation of Linux.

For help configuring CouchDb on Linux, try running couch-config. The linux config file is here:

/etc/couchdb/default.ini
/etc/couchdb/local.ini

You can confirm the above by typing:

couch-config --config-dir

Remember that local.ini will not be effected if you upgrade.

You want to find the bind_address and change it from localhost (127.0.0.1) to the IP address of your server.

On AWS, set the IP to 0.0.0.0 in local.ini:

[httpd]
port = 5984
bind_address = 0.0.0.0

You can use nano or vim or the editor of your choice to edit the ini file. If you are trying to run curl on your AWS server to talk to CouchDb after changing the IP address to 0.0.0.0 then you can just use localhost:

curl http://localhost:5984

In your browser, you can use your elastic ip. Don't forget to open up port 5984 in the security group for your server.

You should probably also turn of the Admin Party in Futon for your AWS server. To do that, just click on the link in the bottom right hand corner of futon:

http://54.XX.XX.XX:5984/_utils

Then assign a user name and password. In your server.js files, you will now have to use an address like this:

http://username:password@elasticip:5984

This is probably not very secure, as I believe you password will be sent across the internet as clear text, so I would consider not picking a top level password that you use for really important accounts. I think there is way to turn on https for couchdb, and I will try to figure that out, as it provides more security.

After you edit the local.ini file, you should restart couchdb:

sudo /etc/init.d/couchdb stop
sudo /etc/init.d/couchdb start

Test your work from the linux command line:

curl http://192.168.2.19:5984/

And then try it from a browser on your Windows machine.

Logging in with HTTP Authentication

Here's how we normally log in to nano:

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

Now let's log in as an adminstrator named ccalvert with an unbreakable password of foobar:

var nano = require('nano')('http://ccalvert:foobar@192.168.2.21:5984');

Error: Document Update Conflict

When you first start with CouchDb, you are likely to get "Document Update Conflict" errors when you try to insert data. This error occurs when you try to do an insert and the document you are trying to insert already exists. To update the document, you have to add a revision number to your insert.

Revision numbers (_rev) are clearly visible in Futon when you look at existing database documents:

_rev: "6-9a046bdac69072ed5075c3addfe015c8"

One way to perform an update is to do this:

Here is the code for doing the above. The parameters here are the Express response object, the JSON data you want to insert, and the name you want to give your to document.

var sendToCouch = function(response, data, docName) { 
    var prog = nano.db.use(dbName);
    prog.get(docName, function(error, existing) {
        if(!error) { 
            console.log("Document exists. Doing Update.");
            data._rev = existing._rev;
            doInsert(response, data, docName);
        }  else {
            console.log("Document does not exist. Doing insert.");
            doInsert(response, data, docName);
        }
    });
}

The key line in the above code is this one, where we add the rev to the document we are inserting if it is an update scenario:

data._rev = existing._rev;

Here is the doInsert method:

var doInsert = function(response, data, docName) {'use strict';
    var prog = nano.db.use(dbName);
    prog.insert(data, docName, function(err, body) {
        console.log('In sendToCouch callback');
        if (!err) {
            response.send({
                "Result" : "Success"
            });
            return;
        } else {
            response.send(500, err);
            return;
        }
    });
};

For a working example, see UnitTestCouchDb01 in JsObjects.

Design Documents

Use design documents to keep a list of your views.

You can use nano to insert design documents.

CouchDb Online Resources

More information:

We will access the database via HTTP and use request:

https://github.com/mikeal/request

Getting started:

http://guide.couchdb.org/draft/tour.html

Once you have it installed on Windows, use the browser:

We want to go to config.html, which is reachable from futon, and set allow_jsonp to true. It is in the http section, about half way down the page:

http://localhost:5984/_utils/config.html

CouchDb Attachments

We often want to add attachments such as an HTML document or image file to our CouchDb database.

app.get("/attachHtml", function(request, response) {'use strict';
   console.log('/attachHtml called');
   
   var fs = require('fs');

    fs.readFile(__dirname + '/Templates/Basic.html', function(err, data) {
        if (!err) {
            var prog = nano.db.use(dbName);
            prog.attachment.insert('basic', 'basic.html', data, 'text/html',
                function(err1, body) {
                if (!err1) {
                    console.log(body);
                } else {
                    console.log(err1);
                    response.send(500, err1);
                }
            });
        } else {
            console.log(err);
            response.send(500, err);
        }
    }); 
});

Sending Back Express and Nano Errors

Send a 500 (Internal Server Error) HTTP Error code:

    function(err, body) {
        if (!err) {
            console.log(body);
            response.send(body);
        } else {
            var cscMessage = "No such record as: " + request.query.docName +
                ". Use a the Get Doc Names button to find " +
                "the name of an existing document."
            err.p282special = cscMessage;
            response.send(500, err);
        }
    }

All that needs to be done is send the error code as the first parameter to response.send:

response.send(500, err);

Here is more information on HTTP code. As you can see, some are error codes, some -- such as 200 -- signify success. Your code (and many other tools) can decide what to do with an HTTP message depending on the code that is send with it:

Note also that I am adding a special field onto the error message. This allows me to send back custom error messages along with any details generated by the Nano error message system.

One the client side we do this:

    var create = function() {
        $.ajax({
            type : 'GET',
            url : '/create',
            dataType : 'json',
            success : function(data) {
                showDebug(data.Result);
            },
            error : showNanoError
        });
    };

    var showNanoError = function(request, ajaxOptions, thrownError) {
        var responseText = JSON.parse(request.responseText);
        if (typeof responseText.p282special !== 'undefined') {
            showDebug(responseText.p282special);
        }
        showDebug(responseText.message);
        showError(request, ajaxOptions, thrownError);
    };

Notice that I have create a special error handler for this kind of message. By sending back a 500 HTTP Error Code we ensure that our error handler will be called. The showNanoError has special processing for Nano messages, then we pass the whole error onto our regular Prog282 error handler. As you recall, it looks like this:

    var showError = function(request, ajaxOptions, thrownError) {
        showDebug("Error occurred: = " + ajaxOptions + " " + thrownError);
        showDebug(request.status);
        showDebug(request.statusText);
        showDebug(request.getAllResponseHeaders());
        showDebug(request.responseText);
    };

Clear there are ways to streamline this process, but even if it is overkill, it is nonetheless likely to give you good error support during the development process.

Erica

<https://github.com/benoitc/erica>

Install erica:

git clone git://github.com/benoitc/erica.git
sudo apt-get install erlang

Or, if you want to get into erlang, do this:

sudo apt-get install erlang erlang-doc

Then create something

erica create-webapp
cd myapp
erica push http://192.168.2.18:5984/myapp

Create an app called bar:

erica create-webapp appid=bar
cd bar
erica push http://192.168.2.18:5984/bar

A script to install Erica on Linux.

#!/bin/sh

sudo apt-get install erlang

GIT_DIR=~/git
ERICA_DIR=$GIT_DIR/erica

if [ ! -d "$GIT_DIR" ]; then
    /bin/mkdir $GIT_DIR
fi

if [ ! -d "$ERICA_DIR" ]; then
    cd $GIT_DIR
    git clone git://github.com/benoitc/erica.git
    cd erica
    make
    sudo make install
fi

# build an app
WORK_DIR=~/dev
APP_DIR=$WORK_DIR/goober1

if [ ! -d "$WORK_DIR" ]; then
    /bin/mkdir $WORK_DIR
fi

cd $WORK_DIR
if [ ! -d "$APP_DIR" ]; then
    mkdir $APP_DIR
    pwd
    cd $APP_DIR
    pwd
    erica create-webapp
    cd myapp
    erica push http://127.0.0.1:5984/myapp
fi

CouchApp

To install on Linux:

sudo apt-get install couchdb -y

Or, if you want to try the node version:

npm install -g couchapp