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