per.eight per.eight - 1 month ago 7
Node.js Question

Node.js Socket.io and Express: Sending data continuously to the client other than the setInterval method

I've been fiddling around with socket.io and express. And I,m using Mongoose in this project. I have this code:

Server

io.on('connection', function (socket) {
setInterval(function(){
Data.find({}, {name:1, _id:0}, {sort : { _id : -1 }}, function (err, data) {
if (err) {
console.log(err);
} else {
socket.emit('data', {datas: data});
};
})
}, 500);
});


Client

var socket = io.connect();
socket.on('data', function (data) {
if (data) {
$('#names').html('');
$.each(data.datas, function (index, value) {
$('#names').append('<li>'+ value.name +'</li>')
})
};
});


Is it proper to execute setInterval on socket.io connection to load the necessary data from the database to send it continuously to the client? Will this affect the server in performance? If it does, whats the best way to fetch data from mongodb to the client side continuously? Is there a way to watch (or something like database trigger) the collections in mongodb if someone from the user/client side adds data? In my code, Am I doing the right thing in placing the mongodb query inside the setInterval function? I'm new in using node.js, socket.io and mongodb. Can someone direct me to the right path? Thanks in advance!

Answer

Here is what I have accomplished rather than using the setInterval method in case someone wants to know how i did it on my project. Thanks to @Mariusz comment

"how about a simple HTTP webservice called by the one who writes to the database?"

gave me an idea. Instead, what I did is add an event click method on the form submit with socket.emit('client_data', {'data': $(this).serializeArray()}); to send the data to the server. Then on the server I call socket.on('client_data') method to fetch the data from the client to save it to the database and called io.sockets.emit method from the callback to send back the updated data to the client (reference on how to send responses to clients). Sorry if can't explain it even better, but here's the code so you could figure it out.

Client

<script src="/js/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<form id="form" method="post">
    <label for="name">Name: <input id="text"type="text" name="name"></label>
    <button id="submit" name="submit">save</button>
</form>
<ul id="names">
{% if datas %}
    {% for data in datas %}
    <li>{{data.name}}</li>
    {% endfor %}
{% else %}
    <li>No data</li>
{% endif %}
</ul>

<script>
$(document).ready(function(){
    var socket = io.connect();
    socket.on('data', function (data) {
        if (data) {
            $('#names').html('');
            $.each(data.datas, function (index, value) {
                $('#names').append('<li>'+ value.name +'</li>')
            })
        };
    });

    $('#form').on('submit', function(e){
        e.preventDefault();
        socket.emit('client_data', {'data': $(this).serializeArray()});
        $('#text').val('').focus();
    })
});
</script>

Server

io.on('connection', function (socket) {
    socket.on('client_data', function(data){
        Data.create({
            name: data.data[0].value
        }, function (err, newData) {
            console.log(newData.name + ' is now saved in the database.')
            Data.find({}, {name:1, _id:0}, {sort : { _id : -1 }}, function (err, data) {
                if (err) {
                    console.log(err);
                } else {
                    io.sockets.emit('data', {datas: data});
                };
            })
        })
    });
});

Now everytime a user/client updates the data, all the page will be updated as well without using setInterval to refresh the data. Hope it helps!