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

ForwardJS - RethinkDB - Getting Started

ForwardJS - RethinkDB - Getting Started

Jorge Silva

July 30, 2015
Tweet

More Decks by Jorge Silva

Other Decks in Programming

Transcript

  1. RethinkDB
    The database for the
    realtime web
    ForwardJS
    San Francisco, California
    July 30, 2015

    View full-size slide

  2. Jorge Silva
    @thejsj
    Developer Evangelist @ RethinkDB

    View full-size slide

  3. Schedule
    1. What is RethinkDB?
    2. RethinkDB query language
    3. Working with changefeeds
    4. Using RethinkDB with Node.js
    5. Tutorial: Building a chat app

    View full-size slide

  4. Introduction
    What is RethinkDB?

    View full-size slide

  5. 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 full-size slide

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

    View full-size slide

  7. Built for Realtime Apps
    • Having your database push
    changes keeps your database as
    the central source of truth
    • Having a central source of truth
    simplifies your architecture

    View full-size slide

  8. Power and Convenience
    • Highly expressive query language
    • Relational features like table joins
    • Powerful admin UI with point-
    and-click cluster management

    View full-size slide

  9. RethinkDB Structure
    Database → Table → Document
    MySQL: Database → Table → Row
    MongoDB: Database → Collection → Document

    View full-size slide

  10. 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 full-size slide

  11. Differences with Firebase
    • Firebase is a cloud service, not an
    open-source database
    • Because Firebase is not a database,
    it has limited querying abilities
    • Firebase is made to be queried
    from the browser

    View full-size slide

  12. Differences with MongoDB
    • RethinkDB supports joins and
    subqueries
    • MongoDB only supports the
    traditional query-response model.
    You can't subscribe to queries.

    View full-size slide

  13. Introduction to ReQL
    RethinkDB query language

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. Sample ReQL Queries
    r.table("users")
    .filter(r.row("age").gt(30))
    r.table(“posts")
    .eqJoin(“userId”, r.table(“users”))
    .zip()
    r.table("posts")
    .filter({status: "draft"})
    .update({status: "published"})

    View full-size slide

  21. ReQL Commands
    • Transformations: map, orderBy, skip, limit, slice
    • Aggregations: group, reduce, count, sum, avg,
    min, max, distinct, contains
    • Documents: row, pluck, without, merge,
    append, difference, keys, hasFields, spliceAt
    • Writing: insert, update, replace, delete
    • Control: forEach, range, branch, do, coerceTo,
    expr

    View full-size slide

  22. ReQL Commands
    • Transformations: map, orderBy, skip, limit, slice
    • Aggregations: group, reduce, count, sum, avg,
    min, max, distinct, contains
    • Documents: row, pluck, without, merge,
    append, difference, keys, hasFields, spliceAt
    • Writing: insert, update, replace, delete
    • Control: forEach, range, branch, do, coerceTo,
    expr

    View full-size slide

  23. ReQL Commands
    • Transformations: map, orderBy, skip, limit, slice
    • Aggregations: group, reduce, count, sum, avg,
    min, max, distinct, contains
    • Documents: row, pluck, without, merge,
    append, difference, keys, hasFields, spliceAt
    • Writing: insert, update, replace, delete
    • Control: forEach, range, branch, do, coerceTo,
    expr

    View full-size slide

  24. ReQL Commands
    • Transformations: map, orderBy, skip, limit, slice
    • Aggregations: group, reduce, count, sum, avg,
    min, max, distinct, contains
    • Documents: row, pluck, without, merge,
    append, difference, keys, hasFields, spliceAt
    • Writing: insert, update, replace, delete
    • Control: forEach, range, branch, do, coerceTo,
    expr

    View full-size slide

  25. ReQL Commands
    • Transformations: map, orderBy, skip, limit, slice
    • Aggregations: group, reduce, count, sum, avg,
    min, max, distinct, contains
    • Documents: row, pluck, without, merge,
    append, difference, keys, hasFields, spliceAt
    • Writing: insert, update, replace, delete
    • Control: forEach, range, branch, do, coerceTo,
    expr

    View full-size slide

  26. Understanding ReQL
    • All queries are executed by the
    database, not the client
    • Client driver translates ReQL queries
    into wire protocol
    • In JS use e.g. the mul and gt
    commands instead of the normal
    operators

    View full-size slide

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

    View full-size slide

  28. Installation
    http://rethinkdb.com/install

    View full-size slide

  29. Running Queries
    https://github.com/thejsj/rethinkdb-workshop

    View full-size slide

  30. Running Queries
    http://localhost:8080/
    http://rethinkdb.thejsj.com:8080/

    View full-size slide

  31. Realtime Updates
    Working with Changefeeds

    View full-size slide

  32. Subscribe to change notifications
    on database queries
    Changefeeds

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  35. 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 full-size slide

  36. 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 full-size slide

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

    View full-size slide

  38. 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 full-size slide

  39. Changefeeds
    r.table("table").get(ID).changes()
    r.table("table").getAll(ID).changes()
    r.table("table").between(X, Y).changes()
    r.table("table").pluck(X, Y, Z).changes()
    r.table("table").filter(CONDITION).changes()
    r.table("table").union(ID).changes()
    r.table("table").map(FUNCTION).changes()
    r.table("table").min(INDEX).changes()
    r.table("table").max(INDEX).changes()
    r.table("table").orderBy(INDEX)
    .limit(N).changes()
    Commands that currently
    work with changefeeds:

    View full-size slide

  40. Using Changefeeds

    View full-size slide

  41. Building Web Apps
    Using RethinkDB in Node

    View full-size slide

  42. Client Driver
    • Use a RethinkDB client driver to
    access the database in your app
    • Official drivers available for Ruby,
    Python, and JavaScript
    • Third-party drivers available for
    other languages like Go and Clojure

    View full-size slide

  43. >
    Client Driver
    Install the JS client driver from
    npm in your Node.js project:
    $ npm install rethinkdb --save

    View full-size slide

  44. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob”}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    Add Bob to the “users” table

    View full-size slide

  45. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob"}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    Import the RethinkDB module

    View full-size slide

  46. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob”}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    Connect to the database

    View full-size slide

  47. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob”}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    ReQL query that inserts a record

    View full-size slide

  48. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob”}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    Run the query on a connection

    View full-size slide

  49. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob"}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    });
    Display query response

    View full-size slide

  50. Client Driver
    var r = require("rethinkdb");
    r.connect().then(function(conn) {
    return r.table("users")
    .insert({name: “Bob"}).run(conn)
    .finally(function () { conn.close(); });
    }).then(function(output) {
    console.log(output);
    }).error(function(err) {
    console.log("Failed:", err);
    });
    Handle errors emitted by Promise

    View full-size slide

  51. Using Changefeeds
    r.connect().then(function(conn) {
    return r.table("fellowship")
    .changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, item) {
    console.log(item);
    });
    });
    Display every change on the “fellowship” table

    View full-size slide

  52. Using Changefeeds
    Attach a changefeed to the table
    r.connect().then(function(conn) {
    return r.table("fellowship")
    .changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, item) {
    console.log(item);
    });
    });

    View full-size slide

  53. Using Changefeeds
    Iterate over every value passed into the cursor
    r.connect().then(function(conn) {
    return r.table("fellowship")
    .changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, item) {
    console.log(item);
    });
    });

    View full-size slide

  54. Using Changefeeds
    r.connect().then(function(conn) {
    return r.table("fellowship")
    .changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, item) {
    console.log(item);
    });
    });
    Display received changes in the console

    View full-size slide

  55. Using Socket.io
    • Powerful framework for realtime
    client/server communication
    • Supports WebSockets, long
    polling, and other transports
    • Lets you send JSON messages
    between your app and frontend

    View full-size slide

  56. Socket.io (Server)
    var sockio = require("socket.io");
    var app = require("express")();
    var r = require("rethinkdb");
    var io = sockio.listen(app.listen(8090));
    r.connect().then(function(conn) {
    return r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(5).changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, data) {
    io.sockets.emit("update", data);
    });
    });
    Broadcast score changes over Socket.io

    View full-size slide

  57. Socket.io (Server)
    var sockio = require("socket.io");
    var app = require("express")();
    var r = require("rethinkdb");
    var io = sockio.listen(app.listen(8090));
    r.connect().then(function(conn) {
    return r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(5).changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, data) {
    io.sockets.emit("update", data);
    });
    });
    Load the Socket.io module

    View full-size slide

  58. Socket.io (Server)
    var sockio = require("socket.io");
    var app = require("express")();
    var r = require("rethinkdb");
    var io = sockio.listen(app.listen(8090));
    r.connect().then(function(conn) {
    return r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(5).changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, data) {
    io.sockets.emit("update", data);
    });
    });
    Instantiate Socket.io server

    View full-size slide

  59. Socket.io (Server)
    var sockio = require("socket.io");
    var app = require("express")();
    var r = require("rethinkdb");
    var io = sockio.listen(app.listen(8090));
    r.connect().then(function(conn) {
    return r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(5).changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, data) {
    io.sockets.emit("update", data);
    });
    });
    Attach a changefeed to the query

    View full-size slide

  60. Socket.io (Server)
    var sockio = require("socket.io");
    var app = require("express")();
    var r = require("rethinkdb");
    var io = sockio.listen(app.listen(8090));
    r.connect().then(function(conn) {
    return r.table("players")
    .orderBy({index: r.desc("score")})
    .limit(5).changes().run(conn);
    })
    .then(function(cursor) {
    cursor.each(function(err, data) {
    io.sockets.emit("update", data);
    });
    });
    Broadcast updates to all Socket.io connections

    View full-size slide

  61. Socket.io (Client)


    Real-time web app

    <br/>var socket = io.connect();<br/>socket.on("update", function(data) {<br/>console.log("Update:", data);<br/>});<br/>Receive Socket.io updates on frontend<br/>

    View full-size slide

  62. Socket.io (Client)


    Real-time web app

    <br/>var socket = io.connect();<br/>socket.on("update", function(data) {<br/>console.log("Update:", data);<br/>});<br/>Load the Socket.io client script<br/>

    View full-size slide

  63. Socket.io (Client)


    Real-time web app

    <br/>var socket = io.connect();<br/>socket.on("update", function(data) {<br/>console.log("Update:", data);<br/>});<br/>Connect to the Socket.io server<br/>

    View full-size slide

  64. Socket.io (Client)


    Real-time web app

    <br/>var socket = io.connect();<br/>socket.on("update", function(data) {<br/>console.log("Update:", data);<br/>});<br/>Create handler for “update” messages<br/>

    View full-size slide

  65. Socket.io (Client)


    Real-time web app

    <br/>var socket = io.connect();<br/>socket.on("update", function(data) {<br/>console.log("Update:", data);<br/>});<br/>Display update in browser console<br/>

    View full-size slide

  66. Tutorial: Building a chat app

    View full-size slide

  67. #1: Clone the repository
    Clone From GitHub:
    git clone https://github.com/thejsj/
    rethinkdb-workshop.git
    Download Tarball:
    https://github.com/thejsj/rethinkdb-
    workshop/tarball/master

    View full-size slide

  68. #2: Install Dependencies
    // Go to the project directory
    cd rethinkdb-workshop
    // Install dependencies
    npm install

    View full-size slide

  69. #3: Go to config/default.js
    Update your RethinkDB database
    configuration
    var config = {
    "rethinkdb": {
    "host": "localhost", // or rethinkdb.thejsj.com
    "port": 28015,
    "db" : "rethinkdb_workshop"
    // or GITHUB_HANDLE_rethinkdb_workshop
    },

    View full-size slide

  70. #4: Run Server
    // Start server
    npm run dev // or `node server`

    View full-size slide

  71. #4: Go to server/index.js
    Look for the comments in order to
    write the correct ReQL queries
    // Step 1
    // Write a query

    View full-size slide

  72. Connections
    In this app, the `r` object contains a
    connection.
    r.table("messages").run(r.conn);

    View full-size slide

  73. #5: Switch database
    Connect to the following database, so we can
    all share messages
    var config = {
    "rethinkdb": {
    "host": "rethinkdb.thejsj.com",
    "port": 29015,
    "db" : "GITHUB_HANDLE_rethinkdb_workshop"
    },

    View full-size slide

  74. Next steps
    • Advanced Commands: `r.do`,
    `r.branch`, `r.forEach`
    • Map/Reduce queries
    • Indexes (multi, compound, index
    functions, geospatial)
    • Sharding and replication

    View full-size slide

  75. Questions
    • RethinkDB website:

    http://rethinkdb.com
    • Install RethinkDB:

    http://rethinkdb.com/install/
    • Email me: [email protected]
    • Tweet: @thejsj, @rethinkdb

    View full-size slide