Darren O'Neill

Real time web apps with PostgreSQL and Node.js

This post shows you how to set up PostgreSQL so it triggers a notify event along with additional information to a listening Node.js script. The script will broadcast this information over a WebSocket to the user's browser, all in real time.

PostgreSQL

PostgreSQL allows you to listen for and broadcast notify events. It is as simple as running:

LISTEN myevent;

Then when...

NOTIFY myevent;

...is called any listeners on the myevent channel will be notified along with any attached message.

Firstly create a database table and a stored procedure to issue a notify event. Then add a trigger so that the stored procedure is called after every insert on the table:

CREATE TABLE realtime(
    id SERIAL NOT NULL PRIMARY KEY,
    title character varying(128)
);

CREATE FUNCTION notify_realtime() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
    PERFORM pg_notify('addedrecord', NEW.title);
    RETURN NULL;
END;
$$;

CREATE TRIGGER updated_realtime_trigger AFTER INSERT ON realtime
FOR EACH ROW EXECUTE PROCEDURE notify_realtime();

Here a channel called addedrecord is used to broadcast the title of a newly inserted record.

Next: setup Node.js to listen on addedrecord.

Node.js

The socket.io library is recommended to communicate over WebSockets as it offers the best cross-browser compatibility. Mainly because if the user's browser does not support WebSockets socket.io will fall back to the following options: XHR polling, XHR multipart, Htmlfile, FlashSocket and JSONP polling. This article explains each method.

node-postgres is used to connect to the PostgreSQL database and listen for any notify events on the addedrecord channel. Here is the script:

var io = require('socket.io').listen(9000);
var pg = require ('pg');

var con_string = 'tcp://username:password@localhost/dbname';

var pg_client = new pg.Client(con_string);
pg_client.connect();
var query = pg_client.query('LISTEN addedrecord');

io.sockets.on('connection', function (socket) {
    socket.emit('connected', { connected: true });

    socket.on('ready for data', function (data) {
        pg_client.on('notification', function(title) {
            socket.emit('update', { message: title });
        });
    });
});

The PostgreSQL connection is initialised and listens on the addedrecord channel. When a client connects, the server broadcasts an event named connected along with a message (an object with a variable called connected set to true). Clients listen for this event and act accordingly.

The server expects a connected client to broadcast a ready for data event at some point in the future. On receipt of this and a notify event from PostgreSQL the server will broadcast an update event along with a message, in this case an object containing the newly inserted record's title.

Here is the client side JavaScript to hook this all together:

<script src="inc/socket.io.js"></script>
<script>
    WEB_SOCKET_SWF_LOCATION = 'inc/WebSocketMain.swf';
    var socket = io.connect('http://localhost:9000');
    socket.on('connected', function (data) {
        socket.emit('ready for data', {});
    });
    socket.on('update', function (data) {
        console.log(data.message.payload);
    });
</script>