-
Notifications
You must be signed in to change notification settings - Fork 3
ExpressJS and OrientDB
In this tutorial we assume that you already have an understanding about how web sites works, about how javascript works and that you are interested about what and how OrientDB works with Node.js.
In order to complete this tutorial, you need to have installed and working:
- Node.js: check it with the command
node -v
(on my computer it printsv0.8.16
). In order to install Node.js on your computer, follow the instructions. - expressjs: check it with the command
express -V
(on my computer it prints3.0.5
). In order to install express, typenpm install -g express
(may required root access). - OrientDB: we assume that it's running on your computer. In order to install it, follow the instuctions. This tutorial uses version 1.3.0.
First, let's make a bare minimum express js app. Open up a console/terminal and type
express --sessions tutorial
Then
cd tutorial
npm install -d
node app.js
Express will report
Express server listening on port 3000
head over here and see express working as expected.
Create an blog
database on OrientDB: you can do that using OrientDB Studio or using the OrientDB console with the command
create database local:/home/federico/materiale/works_My/orientdb-graphed-1.3.0/databases/blog admin admin local graph
(don't forget to adjust the path)
Open the package.json
file and add the Node.js OrientDB driver to the list of dependencies:
"orientdb": "*"
Now require the driver in app.js
:
var orientdb = require("orientdb");
Right after it, add the following code
//Previous code omitted
var dbConfig = {
username:"admin",
password:"admin",
database:"test",
host: "localhost",
port: 2424,
database_type: "document", //Optional. Default: document.
storage_type: "local" //Optional. Default: local.
};
var server = new orientdb.Server(serverConfig);
var db = new orientdb.GraphDb("blog", server, dbConfig);
db.open(function(error) {
if (error) {
throw error;
}
console.log("Successfully connected to OrientDB");
});
//Subsequent code omitted
Go back to the terminal, interrupt the running node
process with CTRL+C
, run npm install -d
again to download OrientDB Node.js driver, then restart the app with node app.js
. You'll now see:
Express server listening on port 3000
Successfully connected to OrientDB
Well done!
Right below the console.log
statement in db.open
callback, add this snipped
routes.init(db, function(error) {
if (error) {
throw error;
}
});
Then open index.js
in routes
folder. At its top, add the line module.db = null;
. Then put the following function at the end of the file
exports.init = function(orient, callback) {
module.db = orient;
};
This way, our routes
module now has a private db
property that allows us to communicate with OrientDB.
We are going to programmatically add some classes to our blog database, but only IF they are missing.
Open file index.js
in routes
folder and add the following function
function ensureSchemaIsSetup(callback) {
if (module.db.getClassByName("Post") === null) {
module.db.createClass("Post", "OGraphVertex", callback);
}
if (module.db.getClassByName("Tag") === null) {
module.db.createClass("Tag", "OGraphVertex", callback);
}
}
Now get exports.init
function and, below module.db
assignement, call ensureSchemaIsSetup
so that it now looks like this:
exports.init = function(orient, callback) {
module.db = orient;
ensureSchemaIsSetup(callback);
};
Open file index.js
in routes
folder and modify the index
function so that it looks like:
exports.index = function(req, res) {
module.db.query("SELECT FROM Post ORDER BY creation_date DESC", function(error, results) {
res.render("index", {
title: "Express + OrientDB blog",
posts: results
});
});
};
The important code here is the usage of the command
function: first argument is the query to execute, an optional callback is the second argument.
Then open file index.jade
in views
folder and modify it so that it looks like:
extends layout
block content
h1= title
p Welcome to #{title}
if posts.length > 0
each post in posts
p
b= post.title
p= post.text
p= post.creation_date.toLocaleDateString()
else
h3 There are no posts in this blog!
Restart the app to see our blog complaining for having no blog posts to show. Well done for now: it's time make some new posts!
Open file index.jade
and append the following line
a(href="/new_post") Insert new blog post
Refreshing the index, you should see a link pointing to http://localhost:3000/new_post
.
Create a new file called new_post.jade
in views
folder. Type in the following code:
extends layout
block content
h1= title
form(action="new_post",method="post")
p
label Title
input(name="title",type="text")
p
label Text
textarea(name="text",rows="5",cols="40")
input(type="submit")
Now open file index.js
in routes
folder and add two new functions:
exports.new_post_form = function(req, res) {
res.render("new_post", { title: "New post" });
};
exports.new_post = function(req, res, next) {
var post = {
title: req.body.title,
text: req.body.text,
creation_date: new Date()
};
module.db.createVertex(post, { "class": "Post" }, function(err) {
if (err) return next(err);
res.redirect("/");
});
};
The important code here is the createVertex
function: first argument if the vertex data, then an optional hash of options (if you are using a specific class, you need to specify it here) and an optional callback.
Wire them to the router: open file app.js
in the root folder and below line app.get('/users', user.list);
add:
app.get('/new_post', routes.new_post_form);
app.post('/new_post', routes.new_post);
Now restart the application and try inserting some new posts. Is it working? Are posts sorted in reverse chronological order? Well done!
Let's link our blog posts to some tags.
First add the tag field to new blog post form: open file new_post.jade
in views
folder and add the following code above the submit button
p
label Tags(comma separated)
input(name="tags",type="text")
Then we need to handle this new field. We are going to check if a submitted tag already has an associated vertex: if the vertex doesn't exist, create it, if it exists, load it and put it into a list of tag vertexes that will then be linked to the submitted post.
Modify exports.new_post
in file index.js
in folder routes
so that it looks like:
exports.new_post = function(req, res, next) {
function fetchOrCreateTag(tagName, callback) {
tagName = tagName.trim();
module.db.command("select from Tag where name = '" + tagName + "'", function(err, results) {
if (err) return callback(err);
if (results.length === 0) {
module.db.createVertex({ name: tagName }, { "class": "Tag" }, function(err, tagVertex) {
callback(null, tagVertex);
});
} else {
callback(null, results[0]);
}
});
}
function fetchTagVertexes(callback) {
if (!req.body.tags || req.body.tags.trim() === "") {
callback(null, []);
return;
}
var tagStrings = req.body.tags.trim().split(",");
var tagsAccumulator = [];
for (var idx = 0; idx < tagStrings.length; idx++) {
fetchOrCreateTag(tagStrings[idx], function(err, tagVertex) {
if (err) return callback(err);
tagsAccumulator.push(tagVertex);
if (tagStrings.length === tagsAccumulator.length) {
callback(null, tagsAccumulator);
}
});
}
}
fetchTagVertexes(function(err, tags) {
if (err) return next(err);
var post = {
title: req.body.title,
text: req.body.text,
creation_date: new Date()
};
module.db.createVertex(post, { "class": "Post" }, function(err, post) {
if (err) return next(err);
if (tags.length === 0) {
res.redirect("/");
return;
}
for (var idx = 0; idx < tags.length; idx++) {
module.db.createEdge(post, tags[idx], { label: "tag" }, function(err, edge) {
if (err) return next(err);
tags.pop();
if (tags.length === 0) {
res.redirect("/");
}
});
}
});
});
};
The first two functions, fetchOrCreateTag
and fetchTagVertexes
, do what they say: the former check if the given tag already exists and creates it if not.
Then we wrap the previous function body so that it is a callback of fetchTagVertexes
(this way we are sure all the given tags are already there, ready to be linked to out blog post): we create the post as before and then we link it to each tag, consuming the previously created array. When the last tag has been linked, we redirect to the homepage as we did before.
The important piece of code here is the createEdge
function, which links two vertexes: the first two arguments are the vertexes involved or their RIDs, the third is an optional hash of data, the forth is the callback.
To show the tags in the posts list, we need to modify the query so that it fetches also linked vertexes: we'll use a fetch plan. Go to function exports.index
and modify it so that it looks like:
exports.index = function(req, res) {
module.db.query("SELECT FROM Post ORDER BY creation_date DESC", { fetchPlan: "*:2" }, function(error, results) {
res.render('index', {
title: 'Express + OrientDB blog',
posts: results
});
});
};
The edit file index.jade
in folder views
and below the code p= post.creation_date.toLocaleDateString()
add the following snippet:
if post.out && post.out.length > 0
p Tags:
each toTagEdge in post.out
span= toTagEdge.in.name + "(" + toTagEdge.in.in.length + ") "
The important piece of code here is the new second argument of the command
function. The { fetchPlan: "*:2" }
hash tells OrientDB to load the vertexes of type Post and their linked vertexes/edges until the second level in the hierarchy.
Therefore, given the structure of our graph, we expect, for each post, a hierarchy like: POST(vertex type, position 0) ==>> edge labeled "tag"(edge type, position 1) ==>> TAG(vertex type, position 2).
Time to run it: restart the app, insert a new post, type some tags separated by a comma and submit the form.
Like it? :)
Don't forget to give us feedback: is this tutorial unclear? would you like an error corrected? Open an issue and tell us.
Thank you for your attention.
Thank you Federico Fissore for this great tutorial.