spjy
spjy

Reputation: 467

Rethinkdb change feed rendering with jQuery

I'm currently trying to figure out how to use the change feed from RethinkDB.

I have a table called Calls and upon the insertion, deletion, and updating of it, I would like to stream the changes.

Right now, I have the function to load calls initially and then return changes:

r.db('test').table('Calls').run(function(err, cursor) {
    if (err) throw err;
    socket.emit('load calls', cursor);
});

r.db('test').table('Calls').orderBy({index: r.desc('call_number')})
.changes().run(function(err, cursor) {
    if (err) throw err;
    cursor.each(function(err, record) {
        socket.emit('load calls', record);
    });
});

and on the frontend I append the HTML to the page:

socket.on('load calls', function(docs) {
    docs.map((call) => {
    $('.calls-list').append(`
    <tr id="call_${call.call_number}">
      <td>${call.call_number}</td>
      <td>${call.time}</td>
      <td>${call.type}</td>
      <td>${call.status}</td>
      <td>

     </td>
      <td>${call.location} - ${call.location_cross}</td>
      <td>${call.notes}</td>
      <td><a id="update-call-${call.call_number}" href=""><i class="edit icon yellow text"></i></a> <a id="archive-call-${call.call_number}" href=""><i class="delete icon red text"></i></a></td>
    </tr>
`);
    }
});

The problem here is that the appended HTML is more or less permanent and "independent" from the database; I would like it to be real time and dependent on the database change feed just like in this video. In that case, the database insertion and the orderBy was instant. So in my current problem, if somebody wanted to delete a call, then I would have to emit a socket event and delete the respective HTML element by referencing the ID.

Upvotes: 1

Views: 204

Answers (1)

markwatsonatx
markwatsonatx

Reputation: 3501

I'm not sure I am understanding your question correctly, but I will try and address a few things. First of all, the documents that get returned when you call the changefeed are different from when you call r.db.table (your first call). Your first call will return all the "Call" documents from the database, but the change feed returns a document that includes the previous "Call" document and the new "Call" document. For example, when a new "Call" is added to the database you would see the following:

{
    old_val: null,
    new_val: {id: 1, call_number: x, time: y, ...}
}

For an update to an existing "Call" you would see:

{
    old_val: {id: 1, call_number: x, time: y, ...},
    new_val: {id: 1, call_number: x2, time: y2, ...}
}

And when a "Call" is deleted you would see:

{
    old_val: {id: 1, call_number: x2, time: y2, ...},
    new_val: null
}

You are going to have to handle each scenario differently. You can do this in your frontend by checking to see if there is and old_val and/or a new_val in each document. Something like this:

socket.on('load calls', function(docs) {
    docs.map((call) => {
        if (! call.old_val && ! call.new_val) {
            // this is a call returned from from r.db.table, not the changefeed
            // add call to the dom
        }
        else if (! call.old_val) {
            call = call.new_val;
            // this is a new call added to the db and returned from r.db.table.changes
            // add call.new_val to the dom
        }
        else if (! call.new_val) {
            // this is a delete - remove the row from the dom
        }
        else {
            // this is an update - update the existing row
        }
    }
});

Or you can do some level of filtering on the server and emit different events to the client. Something like this:

r.db('test').table('Calls').orderBy({index: r.desc('call_number')})
.changes().run(function(err, cursor) {
    if (err) throw err;
    cursor.each(function(err, record) {
        if (! record.old_val) {
            // new call added
            socket.emit('load calls', record);
        }
        else if (! call.new_val) {
            // call deleted
            socket.emit('delete calls', record);
        }
        else {
            // call updated
            socket.emit('edit calls', record);
        }
    });
});

Then on the client you would subscribe to each event:

socket.on('load calls', function(docs) {
    // add docs to dom
});

socket.on('edit calls', function(docs) {
    // update docs in dom
});

socket.on('delete calls', function(docs) {
    // delete docs from dom
});

Hope this helps. FYI, I'm the author of the video/sample app you referenced : ) Thanks for watching!

Upvotes: 1

Related Questions