Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RethinkDB+Angular.js: Building realtime web applications

RethinkDB+Angular.js: Building realtime web applications

Jorge Silva

June 16, 2015
Tweet

More Decks by Jorge Silva

Other Decks in Technology

Transcript

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

    View Slide

  2. Jorge Silva
    @thejsj
    Developer Evangelist @ RethinkDB

    View Slide

  3. Introduction
    What is RethinkDB?

    View Slide

  4. 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

    View Slide

  5. 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

    View Slide

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

    View Slide

  7. Introduction to ReQL
    RethinkDB Query Language

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. 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"})

    View Slide

  15. 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

    View Slide

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

    View Slide

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

    View Slide

  18. Realtime Updates
    Working with Changefeeds

    View Slide

  19. Subscribe to change notifications
    on database queries
    Changefeeds

    View Slide

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

    View Slide

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

    View Slide

  22. 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
    }

    View Slide

  23. 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',
    ...
    }
    }

    View Slide

  24. 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'
    }
    }

    View Slide

  25. 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:

    View Slide

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

    View Slide

  27. Building Web Apps
    Using RethinkDB with
    Angular+Node.js

    View Slide

  28. Demo: Realtime Chat

    View Slide

  29. 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

    View Slide

  30. 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

    View Slide

  31. 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

    View Slide

  32. 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

    View Slide

  33. 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

    View Slide

  34. 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

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. 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

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. 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

    View Slide

  41. 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

    View Slide

  42. 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

    View Slide

  43. 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

    View Slide

  44. 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

    View Slide

  45. 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

    View Slide

  46. 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

    View Slide

  47. 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

    View Slide

  48. 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

    View Slide

  49. 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

    View Slide

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

    View Slide

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

    View Slide

  52. 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

    View Slide

  53. 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

    View Slide

  54. 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

    View Slide

  55. 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

    View Slide

  56. 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

    View Slide

  57. 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

    View Slide

  58. 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

    View Slide

  59. 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);
    });
    });
    });
    });

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

  62. 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

    View Slide

  63. 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

    View Slide

  64. 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

    View Slide

  65. 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

    View Slide

  66. 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

    View Slide

  67. 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

    View Slide

  68. 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

    View Slide

  69. 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

    View Slide

  70. 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

    View Slide

  71. Demo: Realtime Chat

    View Slide

  72. Additional Resources
    • RethinkDB website:

    http://rethinkdb.com
    • RethinkDB cookbook:

    http://rethinkdb.com/docs/cookbook
    • RethinkDB installation:

    http://rethinkdb.com/docs/install/

    View Slide

  73. Questions?

    View Slide