I have write code of socket.io and nodejs to fetch value from database and send the value to the client without refresh with setInterval. It is working fine but I don't want to use setInterval function. Because sometimes my database change in hours, sometimes in minuts and sometimes in miliseconds. So I don't want to use setInterval function. I only want that when database value change it automatically update. thats it. I am kinda stuck in it.
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var mysql = require('mysql');
users = [];
connections = [];
disconnection = [];
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
connection.connect(function(error){
if(!!error) {
console.log('Error in connection');
} else {
console.log('Database Connected');
}
});
server.listen(process.env.PORT || 3000);
console.log('Server Running...');
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket) {
connections.push(socket);
console.log('Connected: %s socket connected',
connections.length);
setInterval(function() {
connection.query('select value from piechart',
function(error, rows, fields) {
if(rows.length>0) {
io.sockets.emit('new message', {msg: rows});
//io.sockets.emit('new message', {msg:
'Change.'});
//console.log('Value is fetched from database');
//console.log(rows);
} else {
alert('what will happend');
}
//connection.release();
});
}, 3000);
});
You should take the interval out of the socket scope and make it global.
Then make an interval loop that fetches the value and emits it globally if the value changed from last time it was fetched, to all connected socket clients.
You state that you would like to avoid an interval, but at the end you are going to be needing one.
You can check out mysql-events
A Node JS NPM package that watches a MySQL database and runs callbacks
on matched events.
Another way around it, would be to find all the events that update the value and make them inform your NodeJS process.
But this might be hard if it has components that are out of your control (example : unable of adding code to other process that updates DB)
Related
I have a raspberry Pi that is constantly pushing data to a MySQL database via PHP. I am trying to create a website where I can see the contents of this database realtime.
I've been following this tutorial : http://markshust.com/2013/11/07/creating-nodejs-server-client-socket-io-mysql which shows an example on using socket.io for this purpose. This is working fine from 2 clients, when I add a new note it updates on both browsers. The problem is when I manually add a record to the database from mysql CLI, it does not update. I'm guessing this is because there is no emit happening. How can I implement this?
Server.js:
var mysql = require('mysql')
// Let’s make node/socketio listen on port 3000
var io = require('socket.io').listen(3000)
// Define our db creds
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'node'
})
// Log any errors connected to the db
db.connect(function(err){
if (err) console.log(err)
})
// Define/initialize our global vars
var notes = []
var isInitNotes = false
var socketCount = 0
console.log("connected");
io.sockets.on('connection', function(socket){
// Socket has connected, increase socket count
socketCount++
// Let all sockets know how many are connected
io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function() {
// Decrease the socket count on a disconnect, emit
socketCount--
io.sockets.emit('users connected', socketCount)
})
socket.on('new note', function(data){
// New note added, push to all sockets and insert into db
notes.push(data)
io.sockets.emit('new note', data)
// Use node's db injection format to filter incoming data
db.query('INSERT INTO notes (note) VALUES (?)', data.note)
})
// Check to see if initial query/notes are set
if (! isInitNotes) {
// Initial app start, run db query
db.query('SELECT * FROM notes')
.on('result', function(data){
// Push results onto the notes array
notes.push(data)
})
.on('end', function(){
// Only emit notes after query has been completed
socket.emit('initial notes', notes)
})
isInitNotes = true
} else {
// Initial notes already exist, send out
socket.emit('initial notes', notes)
}
})
Index.html:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
<script>
$(document).ready(function(){
// Connect to our node/websockets server
var socket = io.connect('http://localhost:3000');
// Initial set of notes, loop through and add to list
socket.on('initial notes', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].note + '</li>'
}
$('#notes').html(html)
})
// New note emitted, add it to our list of current notes
socket.on('new note', function(data){
$('#notes').append('<li>' + data.note + '</li>')
})
// New socket connected, display new count on page
socket.on('users connected', function(data){
$('#usersConnected').html('Users connected: ' + data)
})
// Add a new (random) note, emit to server to let others know
$('#newNote').click(function(){
var newNote = 'This is a random ' + (Math.floor(Math.random() * 100) + 1) + ' note'
socket.emit('new note', {note: newNote})
})
})
</script>
<ul id="notes"></ul>
<div id="usersConnected"></div>
<div id="newNote">Create a new note</div>
This is similar to a previous question, where it appears there was no simple way to do this with MySQL.
If you are in an early enough stage of development that you are not tied to MySQL, then I will point out that you can solve this problem with postgresql:
Be pushed to from PHP via PDO library (see docs).
Runs on the Raspberry Pi.
Can detect updates pushed from anywhere on the command-line via pg_notify on a trigger (see docs).
Updates can be subscribed to with NodeJS via the pg package.
On a technical level this will work, but databases in general are not efficient as messaging systems (watch out for the Database-as-IPC anti-pattern). The PHP client could also emit its own notification when things happen, via a message queue, UDP socket, or something else.
I have following code that connect nodejs to mysql. When I run it the first time it work the data print out to the page but when I refresh the page it tell 'This site can’t be reached' 'localhost refused to connect.' I don't understand why I can connect to server only the first time. I use url as localhost:3000/car
var express = require('express');
var app = express();
app.use(express.static(__dirname));
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'joeM',
password : 'versus',
database : 'joe'
});
app.get('/car', function(req, res){
connection.connect();
connection.query('SELECT * FROM test1', function(err, rows, fields) {
if (err) throw err;
var print = '<ol>';
for( var i = 0; i<rows.length; i++){
print +=('<li>ID:' + rows[i].id + ' Brand:' + rows[i].brand +'</li>' );
}
print += '</ol>';
res.send(print);
connection.end();
});
});
app.listen(3000, function(){
console.log('Magic Happen at port: 3000');
});
dont use connection.connect(); in every request and set it out of request block
//Sending UDP message to TFTP server
//dgram modeule to create UDP socket
var express= require('express'), fs= require('fs'),path = require('path'),util = require('util'),dgram= require('dgram'),client= dgram.createSocket('udp4'),bodyParser = require('body-parser'),app = express(), ejs = require('ejs');
var plotly = require('plotly')("Patidar", "ku0sisuxfm")
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(express.static('public'));
//Reading in the html file for input page
app.get('/', function(req, res){
var html = fs.readFileSync('index2.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
//reading in html file for output page
app.get('/output', function(req, res){
var html = fs.readFileSync('index4.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
//Recieving UDP message
app.post('/output', function(req, res){
var once= req.body.submit;
if (once == "Once") {
//Define the host and port values of UDP
var HOST= req.body.ip;
var PORT= req.body.port;
//Reading in the user's command, converting to hex
var message = new Buffer(req.body.number, 'hex');
//Sends packets to TFTP
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
//Recieving message back and printing it out to webpage
client.on('message', function (message) {
fs.readFile('index3.html', 'utf-8', function(err, content) {
if (err) {
res.end('error occurred');
return;
}
var temp = message.toString(); //here you assign temp variable with needed value
var renderedHtml = ejs.render(content, {temp:temp, host: HOST, port: PORT}); //get redered HTML code
res.end(renderedHtml);
//var data = [{x:[req.body.number], y:[temp], type: 'scatter'}];
//var layout = {fileopt : "overwrite", filename : "simple-node-example"};
//plotly.plot(data, layout, function (err, msg) {
//if (err) return console.log(err);
//console.log(msg);
//});
});
});
}
if (once == "continuous") {
var timesRun = 0;
var requestLoop = setInterval(function(){
timesRun += 1;
if(timesRun === 5){
clearInterval(requestLoop);
}
//Define the host and port values of UDP
var HOST= req.body.ip;
var PORT= req.body.port;
//Reading in the user's command, converting to hex
var message = new Buffer(req.body.number, 'hex');
//Sends packets to TFTP
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
//Recieving message back and printing it out to webpage
client.on('message', function (message) {
fs.readFile('index3.html', 'utf-8', function(err, content) {
if (err) {
res.end('error occurred');
return;
}
var temp = message.toString(); //here you assign temp variable with needed value
var renderedHtml = ejs.render(content, {temp:temp, host: HOST, port: PORT}); //get redered HTML code
res.write(renderedHtml);
//var data = [{x:[req.body.number], y:[temp], type: 'scatter'}];
//var layout = {fileopt : "overwrite", filename : "simple-node-example"};
//plotly.plot(data, layout, function (err, msg) {
//if (err) return console.log(err);
//console.log(msg);
//});
});
});
}, 10000);
}
});
//Setting up listening server
app.listen(3000, "192.168.0.136");
console.log('Listening at 192.168.0.136:3000');
I have two button, one button sends the UDP packet once, while a continuous button sends the same UDP packets every 10 seconds. However, when this button is pressed, res.write is repeating the entire output again. Look at the attached pic to see output[![enter image description here][1]][1]
After putting your code into an auto-code-formatter to make it readable, I can see that you are doing this:
client.on('message', function (message) { ...
inside of your app.post() handler. That means that every time your post handler is called, you add yet another client.on('message', ...) event handler. So, after it's called the 2nd time, you have two event handlers, after it's called the 3rd time, you have three and so on.
So, as soon as you have these duplicate, each will get called and you will get duplicate actions applied.
Your choices are to either:
Use .once() for the event handler so it is automatically removed after it fires.
Remove it manually after it fires or when you are done with it.
Add it once outside your app.post() handler so you never add duplicates.
Restructure the way your code works so it doesn't have this type of issue. For example, you have two different handlers for the same incoming message. This is a sign of very stateful code which is more complex to write properly. A better design that isn't stateful in that way would be simpler.
I'm moving my code to a server. This code works and renders database information perfectly on my own server I set up on localhost, however an error from index.html stating "io is not defined" displays when I run the code from my server. For whatever reason socket.io is not being recognized. Also, nothing is shown if I type in localhost:3000 in my browser. Any help would be greatly appreciated.
I have two files, server.js and index.html.
server.js:
var mysql = require('mysql')
var io = require('socket.io').listen(3000)
var db = mysql.createConnection({
host: '127.0.0.1', // Important to connect to localhost after connecting via ssh in screen
user: 'username',
password: '12345',
database: '12345',
port: 3306
})
// Log any errors connected to the db
db.connect(function(err){
if (err) console.log(err)
})
// Define/initialize our global vars
var notes = []
var isInitNotes = false
var socketCount = 0
//Socket.io code below
io.sockets.on('connection', function(socket){
// Socket has connected, increase socket count
socketCount++
// Let all sockets know how many are connected
io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function() {
// Decrease the socket count on a disconnect, emit
socketCount--
io.sockets.emit('users connected', socketCount)
})
socket.on('new note', function(data){
// New note added, push to all sockets and insert into db
notes.push(data)
io.sockets.emit('new note', data)
// Use node's db injection format to filter incoming data
db.query('INSERT INTO notes (note) VALUES (?)', data.note)
})
console.log("10");
// Check to see if initial query/notes are set
if (! isInitNotes) {
// Initial app start, run db query
db.query('SELECT * FROM `Users`')
.on('result', function(data){
// Push results onto the notes array
//console.log(notes);
notes.push(data)
})
.on('end', function(){
// Only emit notes after query has been completed
socket.emit('initial notes', notes)
})
isInitNotes = true
} else {
// Initial notes already exist, send out
socket.emit('initial notes', notes)
}
})
index.html: (thinking the problem is in either the way I'm linking my socket.io.js file, or in the line of code where I declare the variable "socket")
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- Script below works with my server I set up on local host
<script src="http://localhost:3000/socket.io/socket.io.js"></script>-->
<!-- script below properly links to the socket.io.js file in my directory, and throws no errors-->
<script type= "node_modules/socket.io/node_modules/socket.io-client/socket.io.js"></script>
<script>
$(document).ready(function(){
var socket = io.connect('http://localhost:3000'); //LINE OF CODE IN QUESTION
//Code below not really relevant to problem, but still part of my project.
socket.on('initial notes', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].Name + '</li>'
}
$('#notes').html(html)
})
// New note emitted, add it to our list of current notes
socket.on('new note', function(data){
$('#notes').append('<li>' + data.Name + '</li>')
})
// New socket connected, display new count on page
socket.on('users connected', function(data){
$('#usersConnected').html('Users connected: ' + data)
})
// Add a new (random) note, emit to server to let others know
$('#newNote').click(function(){
var newNote = 'This is a random ' + (Math.floor(Math.random() * 100) + 1) + ' note'
socket.emit('new note', {note: newNote})
})
})
</script>
<ul id="notes"></ul>
<div id="usersConnected"></div>
<div id="newNote">Create a new note:</div
SOLVED!
Figured it out. I used "script src="my servers ip address:3000/socket.io/socket.io.js" and then change the variable socket to var socket = io.connect('Servers ip address:3000'); So the answer was to take out localhost all together.
I believe there could be a problem loading Socket.io from your server if it works locally (perhaps a permissions issue?), try loading it from Socket.io CDN to test.
<script src="http://cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>
I am using the mysql plugin for nodejs and it is fantastic at doing everything I need so far.
However I have come across a stumbling block. I have created a MySQL provider that exports a mysql pool:
var mysql = require('mysql');
var mysqlPool = mysql.createPool({
host : '127.0.0.1',
user : 'root',
password : ''
});
mysqlPool.getConnection(function(err, connection) {
connection.query("INSERT INTO ....
I can select, create, insert, etc all fine, but I've come across a task where I would like to run a small SQL string with about 10 different commands together. I've thought about doing one of the following:
Execute a SQL file against a database using mysql
Run a query and enable multipleStatements
I have written some code to execute mysql as a child process, but I would really love to avoid doing this:
var cp = require("child_process");
var cmdLine = "mysql --user=autobuild --password=something newdb < load.sql";
cp.exec(cmdLine, function(error,stdout,stderr) {
console.log(error,stdout,stderr);
});
The problem with option two is I would rather not enable multipleStatements for every query, just this one particular one. I have thought about creating a new connection, but just thinking of other ways this could be done.
TL;DR?
Using NodeJS and MySQL how can I execute the following into a database:
CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20) );
CREATE TABLE sofa (name VARCHAR(20), owner VARCHAR(20) );
CREATE TABLE table (name VARCHAR(20), owner VARCHAR(20) );
Thanks so much for anyone who shares their ideas
You can use the connection option called multipleStatements:
// Works with the pool too.
var connection = mysql.createConnection({multipleStatements: true});
Then, you can pass the queries like these:
connection.query('CREATE 1; CREATE 2; SELECT 3;', function(err, results) {
if (err) throw err;
// `results` is an array with one element for every statement in the query:
console.log(results[0]); // [create1]
console.log(results[1]); // [create2]
console.log(results[2]); // [select3]
});
Here is a big .sql file friendly way to progmatically execute multiple queries against MySQL without using the multipleStatements property and a massive buffer. Please note this is not the most efficient way to upload to mysql.
var mysql = require('mysql');
var fs = require('fs');
var readline = require('readline');
var myCon = mysql.createConnection({
host: 'localhost',
port: '3306',
database: '',
user: '',
password: ''
});
var rl = readline.createInterface({
input: fs.createReadStream('./myFile.sql'),
terminal: false
});
rl.on('line', function(chunk){
myCon.query(chunk.toString('ascii'), function(err, sets, fields){
if(err) console.log(err);
});
});
rl.on('close', function(){
console.log("finished");
myCon.end();
});
Looks like there is a module for this purpose: execsql
This will do the trick:
var express = require("express");
var bodyParser = require("body-parser");
var mysql = require('mysql');
var fs = require('fs');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static(__dirname));
var defaultConnection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database: 'utpDatabase'
});
function dbCall_file (endpoint, operation, settings, filename){
app.post(endpoint, function(request, response){
var data = request.body;
var path = 'path/to/queries/' + filename
var connection = (settings == 'default') ? defaultConnection : settings;
var callback = function(arg){
var query = arg.replace(/{{[ ]{0,2}([a-zA-Z0-9\.\_\-]*)[ ]{0,2}}}/g, function(str, mch){ return data[mch]});
connection.query(query, function(err, rows){
if (!err){
var toClient = (operation == 'select') ? rows : {success: true};
response.send(toClient);
} else {
console.log(err);
response.send({error: err, query: query});
}
});
};
fs.readFile(path, 'utf8', function(err, data){
if (!err){
callback(data);
} else {
callback(err);
}
});
});
};
Then in your .sql file wrap your node variables in double curlies- for example, if you want to query first names for node variable data.firstName from your post call:
SELECT * FROM users WHERE name={{ firstName }}