About RethinkDB

If you need a NoSQL database which works with JSON data, has full support for real-time searching and has a mix of paradigms between SQL and NoSQL, a good option is RethinkDB.

This is an open-source database, which all JSON’s data is persisted into tables like a conventional SQL database, allowing you to run queries among multiple tables using the classic join command. But you can also persist arrays and sub-documents like you are used to do it in MongoDB, CouchDB or PostgreSQL.

There are some cool stuff from RethinkDB like:

GeoSpartial support;

API to handle with Strings, Dates, Booleans and Documents;

Math API;

Map-reduce support;

HTTP client to catch some external data;

Changefeeds which is a realtime searching;

Index support (simple, compound and multi);

Native web admin dashboard;

Building the application

What about building something useful using RethinkDB? To explore the real-time searching, let’s build a simple global timeline using the changefeed feature to list all data in the timeline in real-time, by using Node.js, Express, Socket.IO and RethinkDB.

First, you need to install RethinkDB server, before you start writing the codes below, to install this database I recommend you to read and follow these instructions according to your operating system.

After you install it, run these commands below to initiate the project:

mkdir timeline cd timeline npm init npm install--save express socket.io rethinkdb

Now let’s work! To simplify things we are going to use ES6 code native from Node v6.x.x version and the backend will be a single file code for study purposes, but if you need to build a complex and well structure backend server using RethinkDB, there are some examples using RethinkDB with Koa, Express and Hapi.js.

Well, let’s write the backend server of our application, you can create the file index.js using the code below:

const http = require('http'); const fs = require('fs'); const express = require('express'); const socketIO = require('socket.io'); const r = require('rethinkdb'); const config = require('./config.json'); // Loading Express, HTTP, Socket.IO and RethinkDB const db = Object.assign(config.rethinkdb, { db: 'timeline' }); const app = express(); const server = http.Server(app); const io = socketIO(server); // Connecting to RethinkDB server r.connect(db) .then(conn => { // Index route which renders the index.html app.get('/', (req, res) => { fs.readFile(`${__dirname}/index.html`, (err, html) => { res.end(html || err); }); }); // The changefeed is provided by change() function // which emits broadcast of new messages for all clients r.table('messages') .changes() .run(conn) .then(cursor => { cursor.each((err, data) => { const message = data.new_val; io.sockets.emit('/messages', message); }); }); // Listing all messages when new user connects into socket.io io.on('connection', (client) => { r.table('messages') .run(conn) .then(cursor => { cursor.each((err, message) => { io.sockets.emit('/messages', message); }); }); // Listening the event from client and insert new messages client.on('/messages', (body) => { const { name, message } = body; const data = { name, message, date: new Date() }; r.table('messages').insert(data).run(conn); }); }); server.listen(3000, () => console.log('Timeline Server!')); }) .error(err => { console.log('Can\'t connect to RethinkDB'); throw err; });

There are some important details you must know when you work with RethinkDB, first almost all functions from this module work using callbacks or using Promises, if you choose Promises you can write well structure async functions with better error handlers.

The changefeed (via r.table('messages').changes() ) feature is the database’s subscriber, which is a query observer and returns any modification from a table, the combination with the io.sockets.emit() allows the server to send real-time data for the clients.

Now, let’s create a simple migration script to prepare the database before starts the server. This migration is very common in relational databases. Create the database.js file with the script below:

const r = require('rethinkdb'); const config = require('./config.json'); let conn; r.connect(config.rethinkdb) .then(connection => { console.log('Connecting RethinkDB...'); conn = connection; return r.dbCreate('timeline').run(conn); }) .then(() => { console.log('Database "timeline" created!'); return r.db('timeline').tableCreate('messages').run(conn); }) .then(() => console.log('Table "messages" created!')) .error(err => console.log(err)) .finally(() => process.exit(0));

And don’t forget to create the config.json which contains data to connect in the RethinkDB server:

{ "rethinkdb": { "host": "localhost", "port": 28015 } }

To finish our application, now we must create the index.html which will be the client-side part for the users send messages in the timeline.

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Timeline</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <script src="/socket.io/socket.io.js"></script> </head> <body> <form style="text-align:center;margin:50px 0"> <label for="name">Name:</label> <input type="text" id="name" /> <label for="message">Message:</label> <input type="text" id="message" /> <button type="submit">Send</button> </form> <fieldset style="padding: 20px;width:50%;margin:0 auto"> <legend style="text-align:center">Timeline</legend> <p id="messages"></p> </fieldset> <script> (function() { var socket = io(); var form = document.querySelector('form'); form.addEventListener('submit', function(e) { e.preventDefault(); var name = e.target.querySelector('#name'); var message = e.target.querySelector('#message'); var data = { name: name.value, message: message.value }; socket.emit('/messages', data); e.target.reset(); }); socket.on('/messages', function(data) { var messages = document.querySelector('#messages'); var message = '<b>' + data.name + ':</b> ' + data.message + '<br />'; messages.innerHTML += message; }); })(); </script> </body> </html>

Now we are ready to start this application! But before starting the server you must run in the first time, the database’s migration to create the database and table for this project, so you just need to run this command:

node database.js

If everything goes fine, You can start the server by running:

node index.js

And you can play sending messages in this application accessing the localhost:3000 address.

Conclusion

The RethinkDB is awesome NoSQL! This database can provide full support for real-time applications just using changefeed + socket.io, in this link you can read more about what you can do using changefeeds.

Almost all functions can run using Promises which makes you write better code and you can use easily the ES7 async/await feature to simplify the promises functions too.