full stack development with node.js and nosql
TRANSCRIPT
Full Stack Development with Node.js and NoSQLMatthew D. Groves (@mgroves)
Nic Raboy (@nraboy)
Full Stack?
Where am I?
• All Things Open
• Raleigh, North Carolina
• https://allthingsopen.org/
Who am I?
• Nic Raboy Matthew D. Groves
• Developer Advocate for Couchbase
• @mgroves on Twitter
• Podcast and blog: https://crosscuttingconcerns.com
• "I am not an expert, but I am an enthusiast."
–Alan Stevens
Full Stack Development with Node.js and NoSQLMatthew D. Groves (@mgroves)
Nic Raboy (@nraboy)
The Role of a Full-Stack Developer
Client Frontend
Backend
The Breakdown of a Stack
Database
Web Application Authentication Middleware
Mobile IoTDesktop
Client Frontend
Backend
Our Stack
Couchbase
Node.js
Angular
What is Couchbase?
Couchbase: The Complete Database Solution
Lightweight embedded NoSQL database
with full CRUD and query functionality.
Secure web gateway with synchronization,
REST, stream, batch and event APIs for
accessing and synchronizing data over the
web.
Highly scalable, highly available, high
performance NoSQL database server.
Built-in enterprise level security throughout the entire stack includes user authentication, user and role based data access control
(RBAC), secure transport (TLS), and 256-bit AES full database encryption.
Couchbase Lite Sync Gateway Couchbase Server
EMBEDDED DATABASE SYNCHRONIZATION DATABASE SERVER
SECURITY
Couchbase Lite Overview
Cross-platform support for all major
operating systems and platforms
Built native from the ground up
500kb for most platforms
256-bit AES full database encryption
11
Couchbase LiteEmbedded Database
Sync Gateway Overview
Synchronize data between Couchbase
Lite and Couchbase Server
REST, Stream, Batch, and Event APIs
Pluggable authentication
Fine grained user and role based
access control
Elastically scalable in real-time
12
Sync GatewaySynchronization
Couchbase Server Overview
Scale easily to thousands of nodes
Consistent high performance that
supports millions of concurrent users
Flexible JSON data model
24x365 always-on availability
13
Couchbase ServerDatabase Server
The Power of the Flexible JSON Schema
• Ability to store data in
multiple ways
• De-normalized single
document, as opposed to
normalizing data across
multiple table
• Dynamic Schema to add
new values when needed
The Couchbase Node.js SDK
• Uses the high performance Couchbase C library
• Compatible with Node.js frameworks
• Express, Sails, Hapi, Etc.
• Minimal coding
• No database maintenance via code
• No parsing queries via application code
Building Applications with Node.js SDK
//including the Node.js dependencyvar Couchbase = require("couchbase");
//connecting to a Couchbase clustervar cluster = new Couchbase.Cluster("couchbase://localhost");
//opening a bucket in the clustervar myBucket = cluster.openBucket("travel-sample");
//preparing N1qlvar myQuery = Couchbase.N1qlQuery();
//creating and saving a Documentvar document = {
firstname: "Matt",lastname: "Groves"
};myBucket.insert("my-key", document, function (error, result) { });
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Node.js
function query(sql, done) {var queryToRun = myQuery.fromString(sql);myBucket.query(queryToRun, function (error, result) {
if (error) {console.log("ERROR: ", error);done(error, null);return;
}done(null, result);return;
});}
Demo Time!
Node.js Application Design
Node.js
Server Backend
Angular
Client Frontend
Node.js Separation of Frontend and Backend
• No Jade markup
• API driven
• Less client and server coupling
• The backend can evolve without affecting the frontend
• Frontend can be extended to web as well as mobile
Multiple Frontends & One Backend
The Node.js Backend
Node.js Configuration
1. // app.js2. var Express = require("express");3. var Couchbase = require("couchbase");4. var BodyParser = require("body-parser");5. var Cors = require("cors");6. var UUID = require("uuid");
7. var app = Express();8. var N1qlQuery = Couchbase.N1qlQuery;
9. app.use(BodyParser.json());10.app.use(BodyParser.urlencoded({ extended: true }));11.app.use(Cors());
12.var cluster = new Couchbase.Cluster("couchbase://localhost");13.cluster.authenticate("demo", "123456");14.var bucket = cluster.openBucket("default");
Node.js Configuration
1. // app.js2. app.get("/", (request, response) => {3. response.send("Hello World!");4. });
5. app.listen(3000, () => {6. console.log("Listening at :3000");7. });
Node.js INSERT Document
1. // app.js2. app.post("/person", (request, response) => {3. if (!request.body.firstname) {4. return response.status(401).send({ code: 401, message: "A `firstname` is required." });5. } else if (!request.body.lastname) {6. return response.status(401).send({ code: 401, message: "A `lastname` is required." });7. }8. request.body.type = "person";9. var statement = "INSERT INTO `" + bucket._name + "` (KEY, VALUE) VALUES ($id, $data)10. RETURNING META().id, `" + bucket._name + "`.*";11. var query = N1qlQuery.fromString(statement);12. bucket.query(query, { "id": UUID.v4(), "data": request.body }, (error, results) => {13. if (error) {14. return response.status(500).send({ code: error.code, message: error.message });15. }16. response.send(results[0]);17. });18.});
Node.js SELECT All Documents
1. // app.js2. app.get("/people", (request, response) => {3. var statement = "SELECT META().id, `" + bucket._name + "`.*4. FROM `" + bucket._name + "` WHERE type = 'person'";5. var query = N1qlQuery.fromString(statement).consistency(N1qlQuery.Consistency.REQUEST_PLUS);6. bucket.query(query, (error, results) => {7. if (error) {8. return response.status(500).send({ code: error.code, message: error.message });9. }10. response.send(results);11. });12.});
Node.js SELECT Single Document
1. // app.js2. app.get("/person/:id", (request, response) => {3. if (!request.params.id) {4. return response.status(401).send({ code: 401, message: "An `id` is required." });5. }6. var statement = "SELECT META().id, `" + bucket._name + "`.*7. FROM `" + bucket._name + "` WHERE type = 'person' AND META().id = $id";8. var query = N1qlQuery.fromString(statement);9. bucket.query(query, { "id": request.params.id }, (error, results) => {10. if (error) {11. return response.status(500).send({ code: error.code, message: error.message });12. }13. response.send(results.length > 0 ? results[0] : {});14. });15.});
Node.js DELETE Document
1. // app.js2. app.delete("/person/:id", (request, response) => {3. var statement = "DELETE FROM `" + bucket._name + "`4. WHERE META().id = $id RETURNING META().id, `" + bucket._name + "`.*";5. var query = N1qlQuery.fromString(statement);6. bucket.query(query, { "id": request.params.id }, (error, results) => {7. if (error) {8. return response.status(500).send({ code: error.code, message: error.message });9. }10. response.send(results);11. });12.});
The Angular Frontend
Angular Component
1. import { Component, OnInit } from '@angular/core';2. import { Http, Headers, RequestOptions } from "@angular/http";3. import "rxjs/Rx";
4. @Component({5. selector: 'app-people',6. templateUrl: './people.component.html',7. styleUrls: ['./people.component.css']8. })9. export class PeopleComponent implements OnInit {
10. public people: Array<any>;11. public input: any;
12. public constructor(private http: Http) { }13. public ngOnInit() { }14. public save() { }
15.}
Get All Documents
1. public constructor(private http: Http) {2. this.people = [];3. this.input = {4. firstname: "",5. lastname: ""6. }7. }
8. public ngOnInit() {9. this.http.get("http://localhost:3000/people")10. .map(results => results.json())11. .subscribe(results => {12. this.people = results;13. });14.}
Create New Document
1. public save() {2. if (this.input.firstname != "" && this.input.lastname != "") {3. let headers = new Headers({ "Content-Type": "application/json" });4. let options = new RequestOptions({ headers: headers });5. this.http.post("http://localhost:3000/person", JSON.stringify(this.input), options)6. .map(results => results.json())7. .subscribe(results => {8. this.people.push(results);9. this.input.firstname = "";10. this.input.lastname = "";11. });12. }13.}
More Complex Node.js Queries
Node.js Travel Sample
1. FlightPath.findAll = function (from, to, callback) {2. var statement = "SELECT faa AS fromAirport, geo " +3. "FROM `" + config.couchbase.bucket + "` r" +4. "WHERE airportname = $1 " +5. "UNION SELECT faa AS toAirport, geo " +6. "FROM `" + config.couchbase.bucket + "` r" +7. "WHERE airportname = $2";8. var query = N1qlQuery.fromString(statement);9. db.query(query, [from, to], function (error, result) {10. if (error) {11. return callback(error, null);12. }13. callback(null, result);14. });15.};
Node.js Travel Sample
1. FlightPath.findAll = function (queryFrom, queryTo, leave, callback) {2. var statement = "SELECT r.id, a.name, s.flight, s.utc, r.sourceairport, r.destinationairport,
r.equipment " +3. "FROM `" + config.couchbase.bucket + "` r" +4. "UNNEST r.schedule s " +5. "JOIN `" + config.couchbase.bucket + "` a ON KEYS r.airlineid " +6. "WHERE r.sourceairport = $1 AND r.destinationairport = $2 AND s.day = $3 ” 7. "ORDER BY a.name";8. var query = N1qlQuery.fromString(statement);9. db.query(query, [queryFrom, queryTo, leave], function (error, result) {10. if (error) {11. return callback(error, null);12. }13. callback(null, result);14. });15.};
Node.js Sample Applications
• https://github.com/couchbaselabs/try-cb-nodejs
• https://github.com/couchbaselabs/restful-angularjs-nodejs
Couchbase N1QL Tutorial
• http://query.pub.couchbase.com/tutorial/
Ottoman ODM
4
3Confidential and Proprietary. Do not distribute without Couchbase consent. © Couchbase 2017. All rights reserved.
Ottoman Model
1. var RecordModel = ottoman.model("Record", {2. firstname: { type: "string" },3. lastname: { type: "string" },4. email: { type: "string" },5. created_at: { type: "Date", default: Date.now }6. });
Ottoman Saving
1. var myRecord = new RecordModel({2. firstname: "Matt",3. lastname: "Groves",4. email: "[email protected]"5. });
6. myRecord.save(function (error) {7. if (error) {8. // Error here9. }10. // Success here11.});
Ottoman Finding
1. RecordModel.find({}, function (error, result) {2. if (error) {3. // Error here4. }5. // Array of results here6. });
Where do you find us?
• developer.couchbase.com
• blog.couchbase.com
• @couchbase / @couchbasedev / @mgroves
• forums.couchbase.com
• stackoverflow.com/questions/tagged/couchbase
Frequently Asked Questions
1. How is Couchbase different than Mongo?
2. Is Couchbase the same thing as CouchDb?
3. How did you get to be both incredibly handsome and tremendously intelligent?
4. What is the Couchbase licensing situation?
5. Is Couchbase a Managed Cloud Service?
CouchDB and Couchbase
< Back
memcached
MongoDB vs Couchbase
• Architecture• Memory first architecture• Master-master architecture• Auto-sharding
< Back
• Features• SQL (N1QL)• Full Text Search• Mobile & Sync
Licensing
Couchbase Server Community• Open source (Apache 2)• Binary release is one release behind Enterprise• Free to use in dev/test/qa/prod• Forum support only
Couchbase Server Enterprise• Mostly open source (Apache 2)• Some features not available on Community (XDCR TLS, MDS, Rack Zone, etc)• Free to use in dev/test/qa• Need commercial license for prod• Paid support provided
< Back
Managed Cloud Service (DBaaS)?
Short answer: No.
< Back
Longer answer: Kinda. https://zdatainc.com/couchbase-managed-services/
Longest answer: See me after class.