Published as a tutorial in IBM Cloudant – Bluemix tutorial and demos
In this post I create a cloud application that is based on Bluemix, Cloudant DB and NodeExpress. NodeExpress is used to perform DB operations on CloudantDB
The code can be forked from Devops from bluemix-cloudant-exp. You can also clone the code from Github from bluemix-cloudant-exp
The following NodeExpress routes are created for performing the basic database operations
- a) Displaying the list of books
- b) Adding a book
- c) Updating a book and
- d) Deleting a book
Push the app to Bluemix
a) Push the app to Bluemix using
cf push bluemix-cloudant -p . -m 512M
b) In the Bluemix dashboard add the Cloudant service.
c) Double click the CloudantNoSQLDB
and then click the ‘Launch’ button. This will bring the WebSQL based version of Cloudant DB
c) Next click the link bluemix-cloudant.mybluemix.net
This will start the Webserver and also populate the database.
e) This can be seen in the Cloudant Dashboard for the ‘test’ database which has 3 records shown below
The setup for these routes in the NodeExpress are as follows
app.get('/', routes.index);
app.get('/booklist', booklist.list);
app.get('/newbook', newbook.list);
app.post('/addbook',addbook.list);
app.get('/changebook', changebook.list);
app.post('/updatebook', updatebook.list);
app.get('/rembook', rembook.list);
app.post('/deletebook',deletebook.list);
Setting up the environment for Cloudant’s PouchDB
The first thing is to setup the environment for Cloudant’s Pouch DB by parsing the process.env environment variables as shown below
//Parse the process.env for the port and host that we've been assigned
if (process.env.VCAP_SERVICES) {
// Running on Bluemix. Parse the port and host that we've been assigned.
var env = JSON.parse(process.env.VCAP_SERVICES);
var host = process.env.VCAP_APP_HOST;
var port = process.env.VCAP_APP_PORT;
console.log('VCAP_SERVICES: %s', process.env.VCAP_SERVICES);
// Also parse Cloudant settings.
var cloudant = env['cloudantNoSQLDB'][0]['credentials'];
}
var db = new pouchdb('books'),
remote =cloudant.url + '/books';
opts = {
continuous: true
};
// Replicate the DB to remote
console.log(remote);
db.replicate.to(remote, opts);
db.replicate.from(remote, opts);
Displaying the list of books
Cloudant responds to DB queries as JSON messages. Hence to display the list of books the fields of each document is stored as an array and then displayed using the Jade table in booklist.jade This is shown below
- a) booklist.js
var docs = db.allDocs(function(err, response) {
val = response.total_rows;
var details = "";
j=0;
var booklist = new Array(val);
for(i=0; i < val; i++) {
db.get(response.rows[i].id, function (err,doc){
j++;
booklist[j] = new Array(3);
booklist[j][0] = doc._id;
booklist[j][1] = doc.Title;
booklist[j][2] = doc.author;
details= details + JSON.stringify(doc.Title) + " " + JSON.stringify(doc.author) + "\n";
// Kludge because of Node.js asynchronous handling. To be fixed - T V Ganesh
if(j == val) {
res.render('booklist', {
"booklist" : booklist
});
}
}); // End db.get
} //End for
}); // End db.allDocs
- b) booklist.jade
The jade template simply displays the each booklist as a row in a table
block content
h1= "Display the list of books"
p
strong DocId Title Author
table
each book, i in booklist
tr
td #{book}
p
p
a(href='/') Home
Adding a book
To add a book the book details are obtained using the newbook.jade which display a form
block content
h1= "Add a book"
form#formAddBook(name="addbook",method="post",action="/addbook")
input#inputBookTitle(type="text", placeholder="Title", name="title")
input#inputBookAuthor(type="text", placeholder="Author", name="author")
button#btnSubmit(type="submit") submit
a(href='/') Home
With the values obtained from the form above a document is inserted into the books database as follows
// Get our form values. These rely on the "name" attributes
var Title = req.body.title;
var Author = req.body.author;
db.put({
author: Author,
Title : Title,
}, Title, function (err, response) {
console.log(err || response);
if (err) {
// If it failed, return error
res.send("There was a problem adding the information to the database.");
}
else {
// Redirect to booklist - Display booklist
res.location("booklist");
// And forward to success page
res.redirect("booklist");
}
});
Note: When inserting a document into the books database the docid for the document is set to be the same as the book Title itself
Updating a book
To update a document we need to input the document id. Also the document to be updated should use the “_rev” field which is obtained when we get the document. The values to be input are taken with the changeuser form
block content
h1= "Update a book"
form#formUpdateBook(name="addbook",method="post",action="/updatebook")
input#inputDocId(type="text", placeholder="DocId", name="docid")
input#inputBookTitle(type="text", placeholder="Title", name="title")
input#inputBookAuthor(type="text", placeholder="Author", name="author")
button#btnSubmit(type="submit") submit
a(href='/') Home
The values obtained are used to populate the document as follows
db.get(DocId, function(err, response) {
db.put({
_id: DocId,
_rev: response._rev,
author: Author,
Title : Title,
}, function(err, response) {
if (err) {
// If it failed, return error
res.send("There was a problem updating the information to the database.");
}
else {
// If it worked, redirect to display books
res.location("booklist");
// And forward to success page
res.redirect("booklist");
}
});
});
Deleting a document
To delete a document we need the document id which is taken with the rembook.jade form
block content
h1= "Delete a book"
form#formDeleteBook(name="addbook",method="post",action="/deletebook")
input#DocId(type="text", placeholder="DocId", name="docid")
button#btnSubmit(type="submit") submit
a(href='/') Home
//Deleting document book1
db.get(DocId, function(err, doc) {
db.remove(doc, function(err, response) {
if (err) {
// If it failed, return error
res.send("There was a problem removing the information to the database.");
}
else {
// Redirect to booklist
res.location("booklist");
// And forward to success page
res.redirect("booklist");
}
console.log(err || response);
});
});
In the diagram below docid ‘book3’ is deleted
Important tips
- If you run into issues while create a Jade template then do the following
npm install jade --g
You can check your jade template for correctness using
jade <name of jade template>
If the response is ‘rendered <name of jade template>.html’ then the template is fine.
- If there are problems with deploying the application or if the application crashes you check the cf logs as follows for the issue
cf logs <name of application> --recent
As mentioned the code can be forked from Devops from bluemix-cloudant-exp. You can also clone the code from Github from bluemix-cloudant-exp
Disclaimer: This article represents the author’s viewpoint only and doesn’t necessarily represent IBM’s positions, strategies or opinions
See also
1. Brewing a potion with Bluemix, PostgreSQL & Node.js in the cloud
2. A Bluemix recipe with MongoDB and Node.js
3. Spicing up IBM Bluemix with MongoDB and NodeExpress
4. A Cloud Medley with IBM’s Bluemix, Cloudant and Node.js
Find me on Google+