Create offline web applications on mobile and stationary devices with CouchDB

One of the greatest challenges for mobile applications is the synchronicity of data. An interesting solution to the problem is to use the NoSQL database CouchDB. CouchDB, a document-oriented database, is an alternative to SQL databases. With CouchDB you can use cloud functions on mobile devices, work offline with a locally deployed application on a local data storage, and share data with the rest of the cloud when going online again. In this article, learn the CouchDB concepts by creating and deploying a sample application.

Dietmar Krueger, IT Architect, IBM

Photo of Dietmar KruegerDietmar Krueger works for Application Innovation Services, a Service Line of IBM Global Business Services. He has developed object-oriented software for 17 years. Dietmar has a passion for agile software development, lightweight architectures, and dynamically-typed programming languages.



21 December 2010

Also available in Chinese Japanese Portuguese

Introduction

An SQL synchronicity mechanism based on distributed databases, such as the one embedded in HTML5 browsers, results in complex efforts. Apache CouchDB has an inherent synchronization base. (See Resources for more about CouchDB synchronization.) In this article, learn the CouchDB concepts and technical details by walking through a typical usage scenario. You will create and deploy a prototype of a simple inventory management application.

A similar application based on HTML5 concepts was introduced in my previous developerWorks article, "Create offline Web applications on mobile devices with HTML5," but synchronization wasn't addressed. For this article, I migrated the application using storage and standard synchronization facilities of the CouchDB environment. You can download the source code used in this article from the Download table below.

Overview

Figure 1 shows an overview of the major components of the sample application architecture of the CouchDB and the HTML5/SQL solution from the previous article. Both solutions contain HTML, JavaScript, local data storage, and remote data storage.

Figure 1. Core elements of an offline CouchDB application
Diagram showing the core elements of an Offline CouchDB application, showing both local and remote elements. The elements are described in the text below.
HTML page
The core of the HTML5 and CouchDB application. It has the model role and contains the displayed data and the (default) render information. The HTML elements of the page are organized in a hierarchy of the HTML Document Object Model (DOM) tree.

User-initiated events cause a conventional request-response cycle with a page load and the execution of associated JavaScript functions. Remarkably, these applications consist of a single HTML page without the need to load further HTML pages through the request-response cycles. The whole action is on one page.

JavaScript
Contains the controller functions of the HTML5 and CouchDB application. HTML elements are bound via event handlers to JavaScript functions. JavaScript can access the HTML DOM tree of the application with all user interface elements and can use it as data input for computation. The results of the processing can be presented to the user by modifying the HTML page.
Local data storage
The SQL database of the HTML5 application is based on a schema and uses joins to combine data from multiple tables. The data storage of a CouchDB application has no schemas—the documents are stored and retrieved as JSON documents. There is no need to assemble data using joins.

To manage data, the SQL database uses SQL queries. CouchDB has a RESTful approach: Every document is a RESTful resource with HTTP methods used for requests.

Remote data storages
The application infrastructure consists of a network of data storage nodes replicating to each other. In the world of relational SQL databases, it is necessary to write or manage complicated replication infrastructure.

In the NoSQL CouchDB architecture, a default replication framework is provided. Actually performing the merge of conflicting documents is an application-specific function (see Resources). This is one of CouchDB's most powerful features.

Example application

This section provides an overview of the sample application MyHomeStuff, which provides simple inventory management to keep track of items you own. It is functionally equivalent to the HTML5 version. Figure 2 shows the application in a Firefox® browser on Windows®.

Figure 2. Inventory management system in a Firefox browser on Windows
Screenshot of Inventory management system showing an Overview section, Details for entering more items, and a Replicate section. Following text has more information.

The application on an Android™ web browser is shown below.

Figure 3. Inventory management system on Android
Screenshot of Inventory management system with the same data as the image above, but on a smaller, Android, screen.

The application lets you keep track of owned items. The list on the upper part of the screen gives an overview of all entered items, such as books. By selecting an item in the list, the details (quantity and name) of the item are shown in the middle form. The details of the selected item can be changed using the Update button, or the selected item can be deleted from the application with the Delete button. New items can be created by entering the item's quantity and name in the form and selecting Create.

The user can initiate a replication process in the lower part of the screen. The process is operated by entering the URL of the source and target CouchDB and activating the Replicate button. The target CouchDB can be an existing remote or local database.

HTML details

The HTML page contains declarations, references to the external JavaScript files, and essential HTML elements that form the basic structure of the application. Listing 1 shows the code.

Listing 1. HTML code
<!DOCTYPE html>
<html>
  <head>
  	<title>MyHomeStuff2</title>
  	<script src="/_utils/script/jquery.js"></script>
  	<script src="/_utils/script/jquery.couch.js"></script>
  	<script src="script.js"></script>
  </head>
  <body>
  
    <h3>Overview</h3>
    <ul id="itemData" ></ul>

    <h3>Details</h3>
    <form name="itemForm">
        <input type="hidden" name="id" id="idId" />
        <input type="hidden" name="rev" id="revId"/>
        <label for="amount">Qty: </label>
        <input type="text" name="amount" id="amountId" size = 3/>
        <label for="name">Name: </label>
        <input type="text" name="name" id="nameId" size=12 />
        <br><br>
        <input type="button" id="createId" value="create" />
        <input type="button" id="updateId" value="update" />
        <input type="button" id="deleteId" value="delete" />
    </form>
   
    <h3>Replicate</h3>
    <form>
        <label for="sourceDBId">Source: </label>
        <input id="sourceDBId" type="text"></input>
        <br><br>
        <label for="targetDBId">Target: </label>
        <input id="targetDBId" type="text"></input>
        <br><br>
        <input id="replicateId" type="button" value="replicate"></input>
   </form>
   
  </body>
</html>

Since the jQuery Library is used in the JavaScript part, the HTML page contains no event-handler attributes. The (click) event handlers are bound from the JavaScript code to the HTML form actions.

The JavaScript Library jquery.couch.js is used to interact with the CouchDBs. It simplifies the communication using straightforward JavaScript. For example, you use db.saveDoc(aTask) instead of having to build communications for RESTful CRUD actions (for example, PUT /tutorial/task/4 ...).

For developing more advanced applications, you should use the CouchApp framework. CouchApp consists of a set of scripts that simplifies developing CouchDB applications (see Resources for more information).

JavaScript details

The JavaScript code consists of three main blocks:

  • Initialization functions
  • db (crud) and view refresh functions
  • Replication function

The first block contains the initialization code for the data storage and the view, as shown in Listing 2.

Listing 2. JavaScript refreshItems code
var db = $.couch.db(getCurrentDBName());

function getCurrentDBName() {
    return window.location.pathname.split("/")[1];
}

$(document).ready(function() {
    //1. init stuff
    refreshItems();
    $('#sourceDBId').val(db.name);
    $('#targetDBId').val(db.name + "-copy");
    
    //2. event handler crud stuff
    ...
});

function refreshItems() {
    $("ul#itemData").empty();
      
    db.view("myDesign/myView", {
        success: function(data){
            data.rows.map(function(row) {
            $('ul#itemData').append('<li id="'+row.value._id+'">'
                +row.value.amount
                +" x "
                +row.value.name
                +'</li>');
                     
            $('#'+row.value._id).click(function() {
                $('#idId').val(row.value._id);
                $('#revId').val(row.value._rev);
                $('#amountId').val(row.value.amount);
                $('#nameId').val(row.value.name);
                return false;
            });
            });
        },
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
        });
}

In the code above:

  • An instance of the CouchDB is created. The database name is extracted from the current URL.
  • The document ready function is called after the DOM has been initialized. First, though, it calls the refreshItems function and populates the fields of the replication form with the names of the source and target databases.
  • The refreshItems function queries the existing records and populates the HTML page with the data, as follows:
    • The old data is removed from the DOM tree.
    • CouchDB is queried. The primary tool for querying and reporting CouchDB is views.

      The query is executed with a success handler and an error handler function. The view function makes a RESTful query using an HTTP GET. The view consists of a map function that transforms each document with name and amount fields into key value pairs with the ID as key and the document as value (see the Deployment section for the map function of the View myView).

    • The success handler creates an HTML list element for every value and appends it to the list. An event click handler is added for every list element to respond on a click by populating the fields with the selection.
    • The error handler displays problems with an alert dialog.

The event handlers are in the second part of the refreshItems function, which contains the event handler for the button bar and the list with update, delete, and create. Listing 3 shows the code for update. (Create and delete have a similar structure, so aren't shown here. You can download all the source code for the example application from the Download table below.)

Listing 3. JavaScript update code
...
    //event handler crud stuff
...
    $('input#updateId').click(function(e) {
         
       if ($('#idId').val().length == 0) {
           return;
       }
       
       var aTask = {
           _id: $('#idId').val(),
           _rev: $('#revId').val(),
           amount: $('#amountId').val(),
           name:$('#nameId').val()
       }
       db.saveDoc(aTask, { success: function(resp) {
           refreshItems();
       }});
    });
...

In the code above:

  • The field values of the form are read and validated.
  • If the values are valid, a JSON object is created and the update call will be executed using HTTP PUT for updating.
  • The result of the query is shown in the refreshed HTML page through the success handler.

The code for the replication functions is very dense, as shown in Listing 4.

Listing 4. JavaScript replication code
$('#replicateId').click(function() {
    var sourceDB = $('#sourceDBId').val();
    var targetDB = $('#targetDBId').val();
    $.couch.replicate(sourceDB, targetDB, {
        success: function(data){alert('Replication was performed');},
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
    });
});

In the above code:

  • The field values of the replication form are read.
  • The replication call will be executed.
  • The result of the replications is shown as an alert box, activated through the success or error handler.

Deployment

If you have CouchDB installed on your computer you can run the example. CouchDB has different installers for Linux®, Windows, Mac®, and Android (2.1 or higher; at the writing of this article, the Android port was at 0.50 alpha version, so beware). Alternatively, you can use a hosting service. I successfully tried the free hosting of CouchOne (see Resources).

After installing CouchDB, the container is ready to enter the downloaded application in a few steps.

  1. Create the database for the application and the data.
    • Click Create Database ...
    • In the Create New Database dialog, fill the Database Name field (for example, stuff_db) and click Create.
  2. Create a document with data (for testing purposes).
    • Click New Document.
    • Click Add Field.
    • Enter name in Field and table in Value.

      Confirm with the green check mark or with the tab key.

    • Click Add Field.
    • Enter amount in Field and 3 in Value. Confirm it.
    • Click Save Document.

      Now the first data is ready for a query.

  3. Create a View and save it as Design Document.
    • Select Overview --> stuff_db.
    • Select View: Temporary view... (from the pull-down list at the top left).
    • Enter the Map function:
      function(doc) {
        if (doc.name && doc.amount)
        {
          emit(doc._id, doc);
        }}

      For each document in the database that has name and amount fields with non-null values, a result row is created in the view. The key of the row is the ID of the document; the value is the document itself.

    • Click Run for testing purposes. The result is the key value pair of the entered document.
    • Click Save As...
    • In the Save View As... dialog, fill the Design Document field with _design/myDesign, the View Name: field with myView, and click Save.

      Now you have a design document where the CouchDB application can be stored.

  4. Query the view.
    • Enter the following in the browser:
      http://127.0.0.1:5984/stuff_db/_design/myDesign/_view/myView
    • It responds with the entered data, which looks something like:
      {"total_rows":1,"offset":0,"rows":[
      {"id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "key":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "value":{"_id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "_rev":"3-d107f491d254b01c0135fd1e8dd13e0a",
      "table":null,"name":"table","amount":3}}
      ]}

      (Lines broken artificially for formatting.)

  5. Open the new Design Document with
    http://127.0.0.1:5984/_utils/document.html?stuff_db/_design/myDesign

    and upload Attachments to the Design Document (for adding the application functions).
    • Select Upload Attachment with File, index.html, and click Upload.
    • Select Upload Attachment with File, script.js, and click Upload.
    • Click Save Document.
  6. Open the application by selecting the index.html Value from the _attachments Field of the Design Document with
    http://127.0.0.1:5984/stuff_db/_design/myDesign/index.html
  7. Enter and change some data in the application.

After successfully installing the application, you can deploy it to a different CouchDB database by using the replication mechanism.

  1. To simplify matters, create a new database in the same CouchDB node (for example, new-stuff-db).
  2. Enter the URLs of existing CouchDB databases. In the Source field enter the name of the source database (stuff_db), and in the Target field enter the target URL (new-stuff-db).
  3. Click replicate. The whole database with data and program code will be replicated.

    Newly entered data can be simply transfered from the replication back to the original database in the same way.

  4. Try to replicate the CouchDB database to a remote CouchDB node.

    For example, if you register at the CouchOne Hosting with a subdomain, mysubdomain, and create a database called mydatabase, the target URL you'll use is:

    http://mysubdomain.couchone.com/mydatabase

Summary

In this article you learned about the technical viewpoint for offline applications with CouchDB. A prototype of a simple inventory management application demonstrated the CouchDB technology with JSON storage and standard synchronization facilities.


Download

DescriptionNameSize
Source code for this articleOfflineCouchDBAppSrc.zip3KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Mobile development
ArticleID=602152
ArticleTitle=Create offline web applications on mobile and stationary devices with CouchDB
publish-date=12212010