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

Sacramento Ruby Meetup

Sacramento Ruby Meetup

Intro talk to RethinkDB given at Sacramento Ruby Meetup.

Jorge Silva

May 22, 2015
Tweet

More Decks by Jorge Silva

Other Decks in Programming

Transcript

  1. Realtime apps • More and more apps are built to

    be realtime • Users have come to want and expect this behavior in their apps
  2. 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
  3. 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
  4. RethinkDB Structure Database → Table → Document MySQL: Database →

    Table → Row MongoDB: Database → Collection → Document
  5. Sample Document { "name": "Will Riker", "position": "Commander", "height": 193,

    "birthdate": Mon Aug 19 2335, "ships": [ { "name": "USS Pegasus" }, { "name": "USS Potemkin" }, { "name": "USS Enterprise" }, ], ... }
  6. Introduction to ReQL • ReQL embeds natively into your programming

    language • Compose ReQL queries by chaining commands
  7. Sample ReQL Queries r.table("user") .filter(r.row(“age") > (30)) r.table(“post") .eq_join(“u_id”, r.table(“user”))

    .zip() r.table("fellowship") .filter({:species => "hobbit"}) .update({:species => "halfling"})
  8. 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
  9. Understanding ReQL • Client driver translates ReQL queries into wire

    protocol • In Ruby, the driver users operator overloading for most operations (+, /, >=, not)
  10. Additional ReQL Features • Geospatial indexing for location- based queries

    • Date and time functions for time data • Support for storing binary objects
  11. Changefeeds • The changes command returns a cursor that receives

    updates • Each update includes the new and old value of the modified record
  12. 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 }
  13. 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' } }
  14. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000
  15. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000 Create a Sinatra app
  16. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000 Route to static assets
  17. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000 Create a route to get messages
  18. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000 Create a route to post messages
  19. Basic REST application class MessageApp < Sinatra::Base set :public_folder, 'client'

    get "/" do; ...; end get '/messages' do; ...; end post '/messages' do; ...; end end Rack::Server.start app: MessageApp, Port: 8000 Start app in port 8000
  20. What we need • Listen to changes in our data

    • Push data changes to our client
  21. What we will use • RethinkDB as our database, to

    push data • EventMachine to perform asynchronous queries • Faye for realtime communication with clients
  22. Faye Framework • Open source pub/sub framework for realtime messaging

    • Communication between frontend and backend • Supports Ruby and Node.js on the backend
  23. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Server-side Ruby code
  24. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Create EventMachine event loop
  25. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Connect to the database
  26. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Add your Sinatra app
  27. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Initialize Faye and bind URL route
  28. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Start the changefeed
  29. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Publish the update to a channel
  30. RethinkDB + Faye EM.run do Conn = r.connect host: "localhost"

    class MessageApp < Sinatra::Base ... end App = Faye::RackAdapter.new MessageApp, mount: "/faye" r.table("messages").changes.em_run(Conn) do |err, change| App.get_client.publish('/messages/new', change["new_val"]) end Rack::Server.start app: App, Port: 8000 end Start Faye app on port 8000
  31. Summary • RethinkDB inverts the database model by pushing data

    to your app • By doing this, your database remains as your central source of truth • Having a database that listens to changes in your data dramatically simplifies building realtime apps