Real time, persistent data with RethinkDB

Phil Parsons

Tagged: ,

The last article covered the setup of Socket.io to create a real time data connection between chat windows. In this article we will add RethinkDB to store chat messages and use it’s realtime data feed functionality to notify the chat window of new messages.

This post is part of the Developing for a modern web with React.js series. If you’d like to be notified of new posts in this series you can become a free member. If you don’t want to complete the previous articles before working through this tutorial you can download the code from Github.

Before writing any code you will need to install and setup RethinkDB by following the guide for your platform on their website. Complete the quick start guide but note that you will need to start the database admin server on a different port to the default 8080 as that port conflicts with the Webpack development server.

Once the database is up and running visit the admin UI at http://localhost:9000/#tables and create a new table in the default database (test) called chat_messages.

In a terminal window navigate to the project directory and install the rethinkdb npm package saving it to package.json as a dependency.

Open the socket server code /server/socket-server/index.js and create a connection to the default database. To do this import the rethinkdb client library and setup a connection on the first line of the socket server function by calling the connect method passing an empty options object as, for now, the default options will suffice.

Once connected to the database incoming messages can be inserted into the chat_messages table. Change the message event handler function on the socket connection to store each message as it is received.

The chat now no longer works as the socket connections are not  being notified when a new message is received. To fix this we need to listen for changes to the chat_messages table and notify the socket connections when a message has been added. In RethinkDB this is done by registering a callback on a stream of changes for the chat_messages table using the changes method. Update the socket server code to add this listener.

To be able to identify the connection for the user who sent the message in the changes callback function the way in which connections are stored needs to be updated. We now need an object (or map in computer science terms) in which the key is the user id and the value is the socket connection. Update the connections variable and associated code to use a JavaScript object.

When a new connection is received the new userIdCount variable is incremented and stored in a local constant userId. We need to distinguish the the userId and userIdCount variables so as to encapsulate the value when the connection is made. When the connection is disconnected we simply delete the connection from the Map using the userId value as the key to delete.

Each connection can now be looked up by user id and the changes listener on the chat_messages table can be implemented to send the incoming messages to all users that do not have the same user id as the new message.

When the run method is called it returns a promise. Promises are a way of handling asynchronous operations in a somewhat more succinct way than callback functions. A promise has a then method that allows you to add a series of callback functions that run when the promise is resolved, the work is complete, and in this case that is when the stream of changes to the chat_messages table has been established. You can read more about promises on MDN. The callback function passed to the then method of the promise receives a cursor object that has an each method. The each method can be called to get the value for each new row in the database table (each new message in this case). We use Object.keys to return an array of all the user ids for the stored connections and iterate over this array using the array method forEach sending the new_val of the row, the message, to each connection that does not match the user id of the message, the message sender. The user id from Object.keys is returned as a string so we add the addition sign in front of it to get it’s numeric value. Other alternatives to this are the parseInt function or using a == instead of === to test for equality so that the values are coerced.

The chat application now works as it was before but stores the messages in the database. Start the client and server applications in two terminal windows (npm run webpack-dev and npm run start-dev) if not already running and open the chat window in two browsers tabs sending messages between them to test it still works.

This article is intentionally shorter than the previous articles as the introduction and setup of RethinkDB may well take you a decent amount of additional time to complete. In the next article we will update the application to remove the userIdCount variable and register new users to the chat by capturing their name, email and id in the database.

This post is part of the Developing for a modern web with React.js series. If you enjoyed the tutorial and would like to follow along to future posts please sign up to become a free member.

It's only fair to share...Tweet about this on TwitterShare on FacebookShare on Google+Buffer this pageShare on LinkedInPin on Pinterest

/ 9 Articles

Phil Parsons

2 Comments

  1. Ben

    Awesome! Thanks for writing this 🙂

    Reply

  2. sean

    Hi Phil,

    Did you ever get around to writing the next article?

    I’m enjoying this series and have found it very useful.

    thanks
    Sean

    Reply

Leave a Comment

Your email address will never be published or shared and required fields are marked with an asterisk (*).