├── .gitignore ├── README.md ├── app.js ├── employeeprovider.js ├── package.json ├── public ├── img │ └── rocket.png └── stylesheets │ └── style.css ├── routes ├── index.js └── user.js ├── views ├── employee_edit.jade ├── employee_new.jade ├── index.jade └── layout.jade └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js-Express-MongoDB CRUD sample Application 2 | 3 | This is a simple Node.js CRUD application using MongoDB. 4 | 5 | It is based on 6 | [https://github.com/ijason/NodeJS-Sample-App](https://github.com/ijason/NodeJS-Sample-App) and has the following features: 7 | 8 | + includes Wercker configuration 9 | + application changes to run on Oracle Container Cloud Service 10 | 11 | ### How to run 12 | 13 | npm install 14 | node app.js 15 | 16 | ### Configuration 17 | 18 | MongoDB: `mongodb://mongodb` 19 | 20 | Express: `app.listen(process.env.PORT || 3000);` 21 | 22 | Wercker environment properties: 23 | 24 | + DOCKER\_USERNAME = username for Docker account 25 | + DOCKER\_PASSWORD = password for Docker account 26 | + DOCKER\_TAG = tag of the docker image 27 | + DOCKER\_REPOSITORY = name of the new repository (includes image name) 28 | 29 | ## History 30 | 31 | ### 1.0.0 32 | 33 | - Initial version 34 | 35 | ## License 36 | 37 | The Universal Permissive License (UPL), Version 1.0 38 | 39 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | 5 | var express = require('express') 6 | , routes = require('./routes') 7 | , user = require('./routes/user') 8 | , http = require('http') 9 | , path = require('path') 10 | , EmployeeProvider = require('./employeeprovider').EmployeeProvider; 11 | 12 | var app = express(); 13 | 14 | app.configure(function(){ 15 | app.set('port', process.env.PORT || 3000); 16 | app.set('views', __dirname + '/views'); 17 | app.set('view engine', 'jade'); 18 | app.set('view options', {layout: false}); 19 | app.use(express.favicon()); 20 | app.use(express.logger('dev')); 21 | app.use(express.bodyParser()); 22 | app.use(express.methodOverride()); 23 | app.use(app.router); 24 | app.use(express.static(path.join(__dirname, 'public'))); 25 | app.enable('trust proxy'); 26 | }); 27 | 28 | app.configure('development', function(){ 29 | app.use(express.errorHandler()); 30 | }); 31 | 32 | var employeeProvider= new EmployeeProvider(); 33 | 34 | //Routes 35 | 36 | //index 37 | app.get('/', function(req, res){ 38 | employeeProvider.findAll(function(error, emps){ 39 | res.render('index', { 40 | title: 'Employees', 41 | employees:emps 42 | }); 43 | }); 44 | }); 45 | 46 | //new employee 47 | app.get('/employee/new', function(req, res) { 48 | res.render('employee_new', { 49 | title: 'New Employee' 50 | }); 51 | }); 52 | 53 | //save new employee 54 | app.post('/employee/new', function(req, res){ 55 | employeeProvider.save({ 56 | name: req.param('name'), 57 | title: req.param('title') 58 | }, function( error, docs) { 59 | res.redirect('/') 60 | }); 61 | }); 62 | 63 | //update an employee 64 | app.get('/employee/:id/edit', function(req, res) { 65 | employeeProvider.findById(req.params.id, function(error, employee) { 66 | res.render('employee_edit', 67 | { 68 | _id: employee._id.toHexString(), 69 | name: employee.name, 70 | title: employee.title, 71 | }); 72 | }); 73 | }); 74 | 75 | //save updated employee 76 | app.post('/employee/:id/edit', function(req, res) { 77 | employeeProvider.update(req.params.id,{ 78 | name: req.param('name'), 79 | title: req.param('title') 80 | }, function(error, docs) { 81 | res.redirect('/') 82 | }); 83 | }); 84 | 85 | //delete an employee 86 | app.get('/employee/:id/delete', function(req, res) { 87 | employeeProvider.delete(req.params.id, function(error, docs) { 88 | res.redirect('/') 89 | }); 90 | }); 91 | 92 | app.listen(process.env.PORT || 3000); 93 | -------------------------------------------------------------------------------- /employeeprovider.js: -------------------------------------------------------------------------------- 1 | var Db = require('mongodb').Db, 2 | MongoClient = require('mongodb').MongoClient, 3 | Server = require('mongodb').Server, 4 | ReplSetServers = require('mongodb').ReplSetServers, 5 | ObjectID = require('mongodb').ObjectID, 6 | Binary = require('mongodb').Binary, 7 | GridStore = require('mongodb').GridStore, 8 | Grid = require('mongodb').Grid, 9 | Code = require('mongodb').Code, 10 | BSON = require('mongodb').pure().BSON, 11 | assert = require('assert'); 12 | 13 | EmployeeProvider = function() { 14 | var that = this; 15 | mongodbUri = process.env.MONGOLAB_URI || 'mongodb://mongodb'; 16 | MongoClient.connect(mongodbUri, function(err, db){ 17 | if(err) { return console.dir(err); } 18 | that.db = db; 19 | }) 20 | }; 21 | 22 | 23 | EmployeeProvider.prototype.getCollection= function(callback) { 24 | this.db.collection('employees', function(error, employee_collection) { 25 | if( error ) callback(error); 26 | else callback(null, employee_collection); 27 | }); 28 | }; 29 | 30 | //find all employees 31 | EmployeeProvider.prototype.findAll = function(callback) { 32 | this.getCollection(function(error, employee_collection) { 33 | if( error ) callback(error) 34 | else { 35 | employee_collection.find().toArray(function(error, results) { 36 | if( error ) callback(error) 37 | else callback(null, results) 38 | }); 39 | } 40 | }); 41 | }; 42 | 43 | //find an employee by ID 44 | EmployeeProvider.prototype.findById = function(id, callback) { 45 | this.getCollection(function(error, employee_collection) { 46 | if( error ) callback(error) 47 | else { 48 | employee_collection.findOne({_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)}, function(error, result) { 49 | if( error ) callback(error) 50 | else callback(null, result) 51 | }); 52 | } 53 | }); 54 | }; 55 | 56 | 57 | //save new employee 58 | EmployeeProvider.prototype.save = function(employees, callback) { 59 | this.getCollection(function(error, employee_collection) { 60 | if( error ) callback(error) 61 | else { 62 | if( typeof(employees.length)=="undefined") 63 | employees = [employees]; 64 | 65 | for( var i =0;i< employees.length;i++ ) { 66 | employee = employees[i]; 67 | employee.created_at = new Date(); 68 | } 69 | 70 | employee_collection.insert(employees, function() { 71 | callback(null, employees); 72 | }); 73 | } 74 | }); 75 | }; 76 | 77 | // update an employee 78 | EmployeeProvider.prototype.update = function(employeeId, employees, callback) { 79 | this.getCollection(function(error, employee_collection) { 80 | if( error ) callback(error); 81 | else { 82 | employee_collection.update( 83 | {_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(employeeId)}, 84 | employees, 85 | function(error, employees) { 86 | if(error) callback(error); 87 | else callback(null, employees) 88 | }); 89 | } 90 | }); 91 | }; 92 | 93 | //delete employee 94 | EmployeeProvider.prototype.delete = function(employeeId, callback) { 95 | this.getCollection(function(error, employee_collection) { 96 | if(error) callback(error); 97 | else { 98 | employee_collection.remove( 99 | {_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(employeeId)}, 100 | function(error, employee){ 101 | if(error) callback(error); 102 | else callback(null, employee) 103 | }); 104 | } 105 | }); 106 | }; 107 | 108 | exports.EmployeeProvider = EmployeeProvider; 109 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ExpressTut", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node app" 7 | }, 8 | "dependencies": { 9 | "express": "3.4.0", 10 | "jade": "*", 11 | "mongodb": "1.3.19" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /public/img/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagypeter/nodejs-mongodb-crud/799aafdaca6c4fc284adb3f3164cccb1631d73c5/public/img/rocket.png -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Titillium+Web:300); 2 | 3 | html, 4 | body { 5 | background: #eee url("../img/rocket.png") bottom left / auto 50% no-repeat; 6 | height: 100%; 7 | font-family: 'Titillium Web', sans-serif; 8 | } 9 | 10 | h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { 11 | font-family: 'Titillium Web', sans-serif; 12 | text-align: center; 13 | } 14 | 15 | #employees { 16 | margin: 0 auto; 17 | padding-bottom: 20px; 18 | width: auto; 19 | max-width: 680px; 20 | } 21 | 22 | .container { 23 | width: auto; 24 | } 25 | 26 | .form-signin { 27 | max-width: 330px; 28 | padding: 15px; 29 | margin: 0 auto; 30 | } 31 | .form-signin .form-signin-heading, 32 | .form-signin .checkbox { 33 | margin-bottom: 10px; 34 | } 35 | .form-signin .checkbox { 36 | font-weight: normal; 37 | } 38 | .form-signin .form-control { 39 | position: relative; 40 | font-size: 16px; 41 | height: auto; 42 | padding: 10px; 43 | -webkit-box-sizing: border-box; 44 | -moz-box-sizing: border-box; 45 | box-sizing: border-box; 46 | } 47 | .form-signin .form-control:focus { 48 | z-index: 2; 49 | } 50 | .form-signin input[name="name"] { 51 | margin-bottom: -1px; 52 | border-bottom-left-radius: 0; 53 | border-bottom-right-radius: 0; 54 | } 55 | .form-signin input[name="title"] { 56 | margin-bottom: 10px; 57 | border-top-left-radius: 0; 58 | border-top-right-radius: 0; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * GET home page. 4 | */ 5 | 6 | exports.index = function(req, res){ 7 | res.render('index', { title: 'Express' }); 8 | }; -------------------------------------------------------------------------------- /routes/user.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * GET users listing. 4 | */ 5 | 6 | exports.list = function(req, res){ 7 | res.send("respond with a resource"); 8 | }; -------------------------------------------------------------------------------- /views/employee_edit.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div.container 5 | form.form-signin(method="post") 6 | h2.form-singin-heading= "Edit Employee" 7 | input(name="_id", type="hidden", value=_id) 8 | input.form-control(type="text", name="name", id="editEmployeeName", placeholder="Name", value=name, autofocus) 9 | input.form-control(type="text", name="title", id="editEmployeeTitle", placeholder="Title", value=title) 10 | input(type="submit", value="Update", class="btn btn-lg btn-primary btn-block") 11 | br 12 | a(href="/")!= "Back to Employee List" 13 | -------------------------------------------------------------------------------- /views/employee_new.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div.container 5 | form.form-signin(method="post") 6 | h2.form-singin-heading= title 7 | input.form-control(type="text", name="name", id="editEmployeeName", placeholder="Name", autofocus) 8 | input.form-control(type="text", name="title", id="editEmployeeTitle", placeholder="Title") 9 | input(type="submit", value="Save", class="btn btn-lg btn-primary btn-block") 10 | br 11 | a(href="/")!= "Back to Employee List" 12 | -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div.container 5 | div.page-header 6 | h1 Node.js + MongoDB app 7 | #employees 8 | h2= title 9 | - each employee in employees 10 | div(class="panel panel-primary") 11 | div.created_at(class="hidden")= employee.created_at 12 | div.panel-heading 13 | div.title(class="panel-title")= employee.name 14 | div.panel-body 15 | div(class="col-xs-10 col-md-10")= employee.title 16 | div(class="col-xs-1 col-md-1") 17 | a(href="/employee/" + employee._id.toHexString() + "/edit" class="btn btn-info")!= "Edit" 18 | div(class="col-xs-1 col-md-1") 19 | a(href="/employee/" + employee._id.toHexString() + "/delete" class="btn btn-danger")!= "X" 20 | a(href="/employee/new" class="btn btn-default")!= "Add New Employee" 21 | -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title Node.js + Express + MongoDB App 5 | link(rel='stylesheet', href='//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css') 6 | link(rel='stylesheet', href='/stylesheets/style.css') 7 | body 8 | block content 9 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: node:6.10 2 | build: 3 | steps: 4 | # A step that executes `npm install` command 5 | - npm-install 6 | push: 7 | steps: 8 | # Push to public docker repo 9 | - internal/docker-push: 10 | username: $DOCKER_USERNAME 11 | password: $DOCKER_PASSWORD 12 | tag: $DOCKER_TAG 13 | repository: $DOCKER_REPOSITORY 14 | registry: https://index.docker.io/v2/ 15 | cmd: node pipeline/source/app.js 16 | --------------------------------------------------------------------------------