Slide 1

Slide 1 text

RethinkDB+Angular.js Building realtime web applications AngularJS SF San Francisco, CA June 15, 2015

Slide 2

Slide 2 text

Jorge Silva @thejsj Developer Evangelist @ RethinkDB

Slide 3

Slide 3 text

Introduction What is RethinkDB?

Slide 4

Slide 4 text

What is RethinkDB? • Open source database for building realtime web applications • NoSQL database that stores schemaless JSON documents • Distributed database that is easy to scale

Slide 5

Slide 5 text

Built for Realtime Apps • Subscribe to change notifications from database queries • No more polling — the database pushes changes to your app • Reduce the amount of plumbing needed to stream live updates

Slide 6

Slide 6 text

Sample Document { "name": "Will Riker", "position": "Commander", "height": 193, "birthdate": Mon Aug 19 2335, "ships": [ { "name": "USS Pegasus" }, { "name": "USS Potemkin" }, { "name": "USS Enterprise" }, ], ... }

Slide 7

Slide 7 text

Introduction to ReQL RethinkDB Query Language

Slide 8

Slide 8 text

Introduction to ReQL • ReQL embeds natively into your programming language • Compose ReQL queries by chaining commands

Slide 9

Slide 9 text

Anatomy of a ReQL Query r.table("users") .pluck("last_name") .distinct().count() Number of unique last names

Slide 10

Slide 10 text

Anatomy of a ReQL Query r.table("users") .pluck("last_name") .distinct().count() Access a database table

Slide 11

Slide 11 text

Anatomy of a ReQL Query r.table("users") .pluck("last_name") .distinct().count() Isolate a document property

Slide 12

Slide 12 text

Anatomy of a ReQL Query r.table("users") .pluck("last_name") .distinct().count() Consolidate duplicate values

Slide 13

Slide 13 text

Anatomy of a ReQL Query r.table("users") .pluck("last_name") .distinct().count() Display the number of items

Slide 14

Slide 14 text

Sample ReQL Queries r.table("users") .filter(r.row("age").gt(30)) r.table(“post") .eqJoin(“uId”, r.table(“users”)) .zip() r.table("fellowship") .filter({species: "hobbit"}) .update({species: "halfling"})

Slide 15

Slide 15 text

Additional ReQL Features • Geospatial indexing for location- based queries • Date and time functions for time data • Support for storing binary objects • Execute http requests using r.http

Slide 16

Slide 16 text

Running Queries http://github.com/thejsj/rethinkdb-quickstart

Slide 17

Slide 17 text

http://rethinkdb-chat.thejsj.com:10001/ Running Queries

Slide 18

Slide 18 text

Realtime Updates Working with Changefeeds

Slide 19

Slide 19 text

Subscribe to change notifications on database queries Changefeeds

Slide 20

Slide 20 text

r.table("users").changes() Track changes on the users table Changefeeds

Slide 21

Slide 21 text

Changefeeds • The changes command returns a cursor that receives updates • Each update includes the new and old value of the modified record

Slide 22

Slide 22 text

Changefeeds r.table("users").changes() r.table("users") .insert({name: "Bob"}) Changefeed output: { new_val: { id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bob', ... }, old_val: null }

Slide 23

Slide 23 text

Changefeeds r.table("users").changes() r.table("users") .filter({name: "Bob"}).delete() Changefeed output: { new_val: null, old_val: { id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bob', ... } }

Slide 24

Slide 24 text

Changefeeds r.table("users").changes() r.table("users") .get("362ae837-2e29-4695-adef-4fa415138f90") .update({name: "Bobby"}) Changefeed output: { new_val: { id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bobby' }, old_val: { id: '362ae837-2e29-4695-adef-4fa415138f90', name: 'Bob' } }

Slide 25

Slide 25 text

Changefeeds r.table("players") .orderBy({index: r.desc("score")}) .limit(3).changes() Track top three players by score Chain the changes command to an actual ReQL query:

Slide 26

Slide 26 text

http://rethinkdb-chat.thejsj.com:10001/ Running Changefeed Queries

Slide 27

Slide 27 text

Building Web Apps Using RethinkDB with Angular+Node.js

Slide 28

Slide 28 text

Demo: Realtime Chat

Slide 29

Slide 29 text

What we need • Add http enpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 30

Slide 30 text

What we need • Add http endpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 31

Slide 31 text

What we need • Add http endpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 32

Slide 32 text

What we need • Add http endpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 33

Slide 33 text

HTTP endpoints with Node.js var express = require('express'); var app = express(); var server = require('http').Server(app); app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { // ... }); server.listen(8000); Create HTTP routes for messages

Slide 34

Slide 34 text

var express = require('express'); var app = express(); var server = require('http').Server(app); app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { // ... }); server.listen(8000); Declare POST endpoint HTTP endpoints with Node.js

Slide 35

Slide 35 text

app .post('/message', function (req, res) { return r.table('messages').insert({ text: req.params.text, email: req.params.email, created: (new Date()).getTime() }).run(r.conn); }) .get('/message', function (req, res) { // ... }) Get `messages` table HTTP endpoints with Node.js

Slide 36

Slide 36 text

app .post('/message', function (req, res) { return r.table('messages').insert({ text: req.params.text, email: req.params.email, created: (new Date()).getTime() }).run(r.conn); }) .get('/message', function (req, res) { // ... }) `insert` new document HTTP endpoints with Node.js

Slide 37

Slide 37 text

app .post('/message', function (req, res) { return r.table('messages').insert({ text: req.params.text, email: req.params.email, created: (new Date()).getTime() }).run(r.conn); }) .get('/message', function (req, res) { // ... }) Run the query HTTP endpoints with Node.js

Slide 38

Slide 38 text

var express = require('express'); var app = express(); var server = require('http').Server(app); app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { // ... }); server.listen(8000); Declare GET route HTTP endpoints with Node.js

Slide 39

Slide 39 text

app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { return r.table('messages') .orderBy({ index: 'created'}) .coerceTo('array') .run(r.conn) .then(function (messages) { res.json(messages); }); }) Get `messages` table HTTP endpoints with Node.js

Slide 40

Slide 40 text

app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { return r.table('messages') .orderBy({ index: 'created'}) .coerceTo('array') .run(r.conn) .then(function (messages) { res.json(messages); }); }) Order by time created HTTP endpoints with Node.js

Slide 41

Slide 41 text

app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { return r.table('messages') .orderBy({ index: 'created'}) .coerceTo('array') .run(r.conn) .then(function (messages) { res.json(messages); }); }) Run the query HTTP endpoints with Node.js

Slide 42

Slide 42 text

app .post('/message', function (req, res) { // ... }) .get('/message', function (req, res) { return r.table('messages') .orderBy({ index: 'created'}) .coerceTo('array') .run(r.conn) .then(function (messages) { res.json(messages); }); }) Return the results of the query HTTP endpoints with Node.js

Slide 43

Slide 43 text

What we need • Add http endpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 44

Slide 44 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Creating factory for messages

Slide 45

Slide 45 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Declare factory

Slide 46

Slide 46 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Inject our dependencies

Slide 47

Slide 47 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Declare our messages array

Slide 48

Slide 48 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Add method for adding messages

Slide 49

Slide 49 text

Message Factory (Client) angular.module('rethinkDBWorkshop.services', []) .factory('MessageFactory', MessageFactory); MessageFactory.$inject = ['$http', '$rootScope']; function MessageFactory ($http, $rootScope) { var messageCollection = []; var factory = { insertMessage: insertMessage, getMessageCollection: getMessageCollection, }; factory.getMessageCollection(); return factory; } Add method for getting messages

Slide 50

Slide 50 text

Message Factory (Client) var factory = { insertMessage: function (text) { return $http.post('/message', { text: text, email: config.email }); }, getMessageCollection: function () {} }; Send POST http request

Slide 51

Slide 51 text

Message Factory (Client) var factory = { insertMessage: function (text) { return $http.post('/message', { text: text, email: config.email }); }, getMessageCollection: function () {} }; Send object to be inserted

Slide 52

Slide 52 text

Message Factory (Client) var factory = { insertMessage: function (text) { }, getMessageCollection: function () { return $http.get('/message') .then(function (res) { messageCollection.splice(0, Infinity); res.data.forEach(function (row) { messageCollection.push(row); }); return messageCollection; }); } }; GET messages from server

Slide 53

Slide 53 text

Message Factory (Client) var factory = { insertMessage: function (text) { }, getMessageCollection: function () { return $http.get('/message') .then(function (res) { messageCollection.splice(0, Infinity); res.data.forEach(function (row) { messageCollection.push(row); }); return messageCollection; }); } }; Remove all messages from array

Slide 54

Slide 54 text

Message Factory (Client) var factory = { insertMessage: function (text) { }, getMessageCollection: function () { return $http.get('/message') .then(function (res) { messageCollection.splice(0, Infinity); res.data.forEach(function (row) { messageCollection.push(row); }); return messageCollection; }); } }; Add all messages to array

Slide 55

Slide 55 text

What we need • Add http endpoint for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 56

Slide 56 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Setup socket handler

Slide 57

Slide 57 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Create Socket.io instance

Slide 58

Slide 58 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Listen for new socket connections

Slide 59

Slide 59 text

Node.js Server Create a new database connection var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); });

Slide 60

Slide 60 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Get `messages` table

Slide 61

Slide 61 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Listen to changes in our messages

Slide 62

Slide 62 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Run the query

Slide 63

Slide 63 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Pass a callback to our cursor

Slide 64

Slide 64 text

Node.js Server var io = require('socket.io')(server); io.on('connection', function (socket) { r.connect(config.get('rethinkdb')) .then(function (conn) { r.table('messages') .changes().run(conn) .then(function (cursor) { cursor.each(function (err, row) { socket.emit('message', row.new_val); }); }); }); }); Send new message to the client

Slide 65

Slide 65 text

What we need • Add http endpoints for getting and adding messages • Create an Angular factory for messages • Setup changefeed in Node.js app • Add realtime listener in factory

Slide 66

Slide 66 text

Message Factory with Changefeeds function MessageFactory ($http, $rootScope) { var socket = io.connect('http://' + config.url); var messageCollection = []; socket.on('message', function (message) { $rootScope.$apply(function () { messageCollection.push(message); }); }); var factory = { ... }; return factory; } Add new message handler

Slide 67

Slide 67 text

Message Factory with Changefeeds function MessageFactory ($http, $rootScope) { var socket = io.connect('http://' + config.url); var messageCollection = []; socket.on('message', function (message) { $rootScope.$apply(function () { messageCollection.push(message); }); }); var factory = { ... }; return factory; } Connection to Socket.io server

Slide 68

Slide 68 text

Message Factory with Changefeeds function MessageFactory ($http, $rootScope) { var socket = io.connect('http://' + config.url); var messageCollection = []; socket.on('message', function (message) { $rootScope.$apply(function () { messageCollection.push(message); }); }); var factory = { ... }; return factory; } Listen to new messages on socket

Slide 69

Slide 69 text

Message Factory with Changefeeds function MessageFactory ($http, $rootScope) { var socket = io.connect('http://' + config.url); var messageCollection = []; socket.on('message', function (message) { $rootScope.$apply(function () { messageCollection.push(message); }); }); var factory = { ... }; return factory; } Perform proper scope life cycle

Slide 70

Slide 70 text

Message Factory with Changefeeds function MessageFactory ($http, $rootScope) { var socket = io.connect('http://' + config.url); var messageCollection = []; socket.on('message', function (message) { $rootScope.$apply(function () { messageCollection.push(message); }); }); var factory = { ... }; return factory; } Push message into collection

Slide 71

Slide 71 text

Demo: Realtime Chat

Slide 72

Slide 72 text

Additional Resources • RethinkDB website:
 http://rethinkdb.com • RethinkDB cookbook:
 http://rethinkdb.com/docs/cookbook • RethinkDB installation:
 http://rethinkdb.com/docs/install/

Slide 73

Slide 73 text

Questions?