Web Development

How to Build Real-time Applications Using Node.js and RethinkDB

August 4th, 2016 | By Jscrambler | 5 min read

The great advantage of using Node.js and RethinkDB to build real-time apps is that RethinkDB is awesome NoSQL! Continue reading...

About RethinkDB

If you need a NoSQL database that 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, in which all JSON 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 is some cool stuff from RethinkDB like:

  • GeoSpartial support;

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

  • Math API;

  • Map-reduce support;

  • HTTP client to catch some external data;

  • Changefeeds which is a real-time search;

  • Index support (simple, compound, and multi);

  • Native web admin dashboard;

Building the application

What about building something useful using RethinkDB? To explore 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 the 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-structured backend server using RethinkDB, some examples are 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-structured 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 to the clients.

Now, let’s create a simple migration script to prepare the database before starting 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 to the RethinkDB server:

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


To finish our application, 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


You can send messages in this application by 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. 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.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Javascript

How To Build Authentication in Angular Using Node and Passport

Passport.js provides a simple authentication middleware that you can use with Node.js. Learn how to use it to easily add authentication to your Angular app.

October 17, 2019 | By Jay Raj | 7 min read

Web Security

How To Protect Node.js Apps With Jscrambler

In this post, we're going to walk through the steps to protect your Node.js application with Jscrambler, using our integrations with Grunt and Gulp.

September 16, 2020 | By Jscrambler | 6 min read

Section Divider

Subscribe to Our Newsletter