RethinkDB

Why another database?

A (not so) simple life of a web developer

WAMP / LAMP

(Windows|Linux) + Apache + MySQL + PHP

web server = Apache

database    = MySQL

language    = PHP

Database landscape

... and its evolution

So, why add to this madness?

RethinkDB

The open-source database for the realtime web

Few facts

  • Written in C++
  • First commit: October 3rd, 2009
  • Current version: 2.2 (production-ready)
  • > 11k stars on Github

Official drivers

  • JavaScript
  • Python
  • Ruby
  • Java (under development)

Document store

Stores plain JSONs

Proper NoSQL document

{
    "first_name": "Paweł",
    "last_name": "Świątkowski",
    "born": 1988,
    "company": "Codete",
    "languages": ["Ruby", "JavaScript", "Erlang"],
    "room": "Mad Max"
}

As opposed to...

{
    "first_name": "Paweł",
    "last_name": "Świątkowski",
    "born": 1988,
    "company_id": 12,
    "language_ids": [1, 13, 55],
    "room_id": 158
}

NoSQL databases are not relational databases equivalents!

Text

Text

(or are they?)

Features

A quick tour

ReQL

Expressive query language for difficult times

Principles

  • Built with target language in mind
  • Everything is chainable
  • All queries execute on server
r.db('workers').table('companies').insert({
    name: 'Codete', address: 'Olszańska 7', sector: 'IT'
}).run()

Query

Response

{
    "deleted": 0,
    "errors": 0,
    "generated_keys": [
        "77e35b16-f5bb-41f5-9344-0952199e5152"
    ],
    "inserted": 1,
    "replaced": 0,
    "skipped": 0,
    "unchanged": 0
}
r.db('workers').table('companies').filter({
    sector: 'IT'
}).run()

Query

Response

{
    "address":  "Olszańska 7",
    "id":  "77e35b16-f5bb-41f5-9344-0952199e5152",
    "name":  "Codete",
    "sector":  "IT"
}

Other languages

Python


cursor = r.table("authors").filter(r.row["name"] == "William Adama").run()
for document in cursor:
    print(document)

Ruby


cursor = r.table("authors").filter{|author| author["posts"].count > 2}.run
cursor.each{|document| p document}

Java


Cursor<Map<String, String>> oneEntryLambda = 
  r.db(dbName).table(tableName).filter(
   table -> table.getField("field").eq("456")
  ).run(conn);

(very early version)

Clojure

  
  (-> (r/db "test")
      (r/table "authors")
      (r/get-all ["crap"] {:index "genre"})
      (r/filter (r/fn [row]
                  (r/eq "Stephenie Meyer" (r/get-field row "name"))))
      (r/run conn))

PHP

  
    $result = r\table("tablePhpTest")->map(function($x) {
        return $x('someKey');
    })->run($conn);

(apparently you can't write pretty code in PHP)

JOINS

Wait, joins in NoSQL?

r.db('workers').table('people').insert({
    "first_name": "Paweł",
    "last_name": "Świątkowski",
    "born": 1988,
    "company": "77e35b16-f5bb-41f5-9344-0952199e5152",
    "languages": ["Ruby", "JavaScript", "Erlang"],
    "room": "Mad Max"
})

Query

r.db('workers').table('people').eqJoin(
    'company', r.db('workers').table('companies')).run()

Query

Response

{
    "left": {
        "born": 1988,
        "company":  "77e35b16-f5bb-41f5-9344-0952199e5152",
        "first_name":  "Paweł",
        "id":  "feee3558-a009-48fe-9380-217d2db562f4",
        "languages": [
            "Ruby",
            "JavaScript",
            "Erlang"
        ],
        "last_name":  "Świątkowski",
        "room":  "Mad Max"
    },
    "right": {
        "address":  "Olszańska 7",
        "id":  "77e35b16-f5bb-41f5-9344-0952199e5152",
        "name":  "Codete",
        "sector":  "IT"
    }
}
r.db('workers').table('people').eqJoin(
    'company', r.db('workers').table('companies')).zip().run()

Query

Response

{
    "address":  "Olszańska 7",
    "born": 1988,
    "company":  "77e35b16-f5bb-41f5-9344-0952199e5152",
    "first_name":  "Paweł",
    "id":  "77e35b16-f5bb-41f5-9344-0952199e5152",
    "languages": [
        "Ruby",
        "JavaScript",
        "Erlang"
    ] ,
    "last_name":  "Świątkowski",
    "name":  "Codete",
    "room":  "Mad Max",
    "sector":  "IT"
}

What's more

Also outerJoin and innerJoin supported

Limitations

Very limited support for indices with join

(inherent to NoSQL databases)

Data types

not only JSON

All JSON data types, of course

Time


r.table('events').insert([
    {id: 0, timestamp: new Date()},
    {id: 1, timestamp: r.epochTime(1376436769.923)}
]).run()


r.table('events').between(r.epochTime(1376436769.913),
      r.epochTime(1376436769.933), {index: 'timestamp'}
).run()


[{"id": 1, "timestamp": Date("2013-08-13T23:32:49.923Z")}]

Binary

You can upload files and store them in the database directly.

(... which is probably not the best idea, but you still can)

Geometry

r.table('geo').insert([
  {
    id: 1,
    name: 'San Francisco',
    location: r.point(-122.423246,37.779388)
  },
  {
    id: 2,
    name: 'San Diego',
    location: r.point(-117.220406,32.719464)
  }
])
r.table('geo').indexCreate('location', {geo: true})
r.table('geo').getNearest(
    r.point(-122.422876,37.777128), 
    {maxDist: 100, unit: 'km', index: 'location'}
).run()

Query

Response

[{
    "dist": 0.25295150950901096,
    "doc": {
        "id": 1,
        "location": {
            "$reql_type$":  "GEOMETRY",
            "coordinates": [
                -122.423246,
                37.779388
            ],
            "type":  "Point"
        },
        "name":  "San Francisco"
    }
}]

Geometry (more)

  • line, polygon, circle
  • distance
  • intersection
  • containment
  • ...

Changefeeds

Real-time updates for documents

Subscribe to a feed with callback function



r.table('users').changes().run(conn, function(err, cursor) {
  cursor.each(console.log);
})

{
  old_val: null,
  new_val: {id: 1, name: 'Slava', age: 31}
}

r.table('messages').filter(
  r.row('room_id').eq('#general')
).changes().run(conn, callback)

How about filtering?


r.table('scores').changes().filter(
    r.row('new_val')('score').gt(r.row('old_val')('score'))
)('new_val').run(conn, callback)

How about something crazy?

Administration

Powerful web administration console

Sharding and Replication

Automatic failover

(with enough shards and replicas)

Who's using it?

Platzi

Platzi is an education platform that streams live video alongside realtime discussion. RethinkDB powers live updates and instant messaging in their online courses. The Platzi team chose RethinkDB because its push model helped them enable realtime collaboration between students and educators.

ClientSuccess

ClientSuccess provides a cloud-based platform that helps SaaS providers manage their customer relationships. RethinkDB simplified the way that their application synchronizes data with Salesforce and other sources. 

Jive

Jive Software is a provider of communication and collaboration solutions for business. Jive enables employees, partners and customers to work together.

Questions?

RethinkDB

By katafrakt

RethinkDB

  • 1,590