Why does this updateSockets() function accept a parameter that look like this? - javascript

I am looking at some node.js code that does push notification on a MySQL database.
http://www.gianlucaguarini.com/blog/push-notification-server-streaming-on-a-mysql-database/
There is a polling function.
var pollingLoop = function() {
// Doing the database query
var query = connection.query('SELECT * FROM users'),
users = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(user) {
// it fills our array looping on each user row inside the db
users.push(user);
})
.on('end', function() {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
users: users
});
} else {
console.log('The server timer was stopped because there are no more socket connections on the app')
}
});
};
The particular code segment above that puzzles me is this;
updateSockets({
users: users
});
Why is the argument users: users?
The code for updateSockets() is here;
var updateSockets = function(data) {
// adding the time of the last update
data.time = new Date();
console.log('Pushing new data to the clients connected ( connections amount = %s ) - %s', connectionsArray.length , data.time);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};

{
users : users
}
This code is just a plain objet. The first users is the name of the object property and the second users is just a variable.
You can write like this if you want :
var myUsers = users;
updateSockets({
users: myUsers
});

It's an additional information stored in data
When this code performs emit(data), it sends the packet with parameters user and time (added in updateSockets)
It's the message you want to send

Related

In Node, how to execute sql from global database connection

I am unable to execute the sql, when using the global database connection in node.js.
I have followed the steps as in Azure documentation: https://learn.microsoft.com/en-us/azure/mysql/connect-nodejs and able to display the output on the console. But, I want to put all my Azure SQL database connection in a separate file, but the select query is not printing the output on the console.
DatabaseManager.js
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var sqlConnection = function sqlConnection() {
// Create connection to database
var config =
{
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options:
{
database: 'mydatabase',
encrypt: true
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err)
{
console.log(err)
}
else
{
console.log('CONNECTED TO DATABASE');
}
}
);
}
module.exports = sqlConnection;
app.js
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var azure = require('azure-storage');
var dbconnection = require('./DatabaseManager');
bot.dialog('profileDialog',
(session) => {
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Reading rows from the Table...');
dbconnection("select FNAME from StudentProfile where ID=1"),
function (err, result, fields) {
if (err) throw err;
console.log(result);
}
session.endDialog();
}
Console Output:
Reading rows from the Table...
CONNECTED TO DATABASE
I was expecting the output of FNAME, but nothing is printing on the console. Is there anything, I am missing?
Thank you.
There's a couple of problems here. First off, you should only ever import a module once per file. This is just a performance consideration and won't actually break your code.
Next, pay attention to what you're exporting from your DatabaseManager module. Right now, you're exporting a function that creates the connection and then doesn't do anything with it. We can fix this by using a pattern called a "callback" which lets us provide a function that will then be called with the connection as an argument.
I added a ton of comments to the code explaining things. This code won't run as-is - there's a couple places where I have "do this or this". You'll have to choose one.
var Tedious = require('tedious'); // Only require a library once per file
var Connection = Tedious.Connection;
var Request = Tedious.Request;
// Or using the object spread operator
var { Connection, Request } = require('tedious');
// You called this `sqlConnection`. I'm going to use a verb since it's a
// function and not a variable containing the connection. I'm also going
// to change the declaration syntax to be clearer.
function connect(cb) { // cb is short for callback. It should be a function.
var config = {
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options: {
database: 'mydatabase',
encrypt: true
}
}; // Put a semi-colon on your variable assignments
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err) {
console.log(err);
return; // Stop executing the function if it failed
}
// We don't need an "else" because of the return statement above
console.log('CONNECTED TO DATABASE');
// We have a connection, now let's do something with it. Call the
// callback and pass it the connection.
cb(connection);
});
}
module.exports = connect; // This exports a function that creates the connection
Then back in your main file, you can use it like so.
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require('botbuilder-azure');
var azure = require('azure-storage');
var connect = require('./DatabaseManager'); // renamed to be a verb since it's a function.
bot.dialog('profileDialog', (session) => { // Hey, this is a callback too!
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Creating a connection');
connect((connection) => {
// or with the traditional function notation
connect(function(connection) {
console.log('Reading rows from the Table...');
// Execute your queries here using your connection. This code is
// taken from
// https://github.com/tediousjs/tedious/blob/master/examples/minimal.js
request = new Request("select FNAME from StudentProfile where ID=1", function(err, rowCount) { // Look another callback!
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) { // Iterate through the rows using a callback
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
connection.execSql(request);
});

Azure Node: Access table storage from SQL Azure Easy tables insert function

I'm trying to insert some data into table storage from the SQL Azure EasyTables insert statement but context.execute() is being called before the table is created in table storage which stops my connection even though the code to create a new table is placed before context.execute(). Could some one tell me how I could stall the context.execute function until I finish my table storage set up. Below is my code. Thanks for the help
table.insert(function (context) {
var azure = require('azure-storage');
var tableService = azure.createTableService('NAME', 'KEY');
context.user.getIdentity().then((data) => {
tableService.createTableIfNotExists('UserInfo', function(error, result) {
if (error) {
//do something
}else {
var entGen = azure.TableUtilities.entityGenerator;
var task = {
PartitionKey: entGen.String(context.user.id),
RowKey: entGen.String('1'),
name : entGen.String(data.facebook.claims.name),
email : entGen.String(data.facebook.claims.emailaddress),
createdOn: entGen.DateTime(new Date(Date.UTC(2016, 3, 27))),
};
tableService.insertEntity('UserInfo',task, function (error, result, resp) {
if(!error){
//respond with success message
}else{
//respond with failure message
}
});
}
});
});
context.item.userId = context.user.id;
return context.execute(); //This line is executed before I get success/failure response from table storage
});
This is because getIdentity() returns a Promise object.
The code then((data) => { ... }) will be executed after its being invoked successfully.
More details about how Promise.then() works, pls see here
You can write the code tableService.createTableIfNotExists(...); into a method and call the method in context.execute().
I wrote the tableService.createTableIfNotExists(...); into a new function and then called the function from "use" operation
table.insert.use(insertMiddleware, table.operation);

MongoDB won't return correct data first time round

This is my code:
// Modules
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'mongodb://localhost:27017/affinity';
window.$ = window.jQuery = require('jquery');
var user_data;
$(document).ready(function () {
// Look through db for user
// Flters through the db to find the user and their password to authenticate them in.
userInfo = function (db, callback) {
var username = $('#username').val();
var password = $('#password').val();
var users = db.collection('users');
// Searches through each user in the db to find one which meets conitions.
var cursor = users.find({
"username": username
}, {"limit": 1} ).each(function (err, doc) {
if (doc != null) {
if (doc.password === password) {
user_data = doc;
//window.location.replace(__dirname + '/assets/views/main.html');
} else {
$("#error-hint").css(
'visibility', 'visible'
);
}
} else {
// Skip user if it isn't matching
}
});
console.log(user_data);
}
// Connects to database.
// Inserts all user data to the database.
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Couldn\'t connect to the mongoDB server. \nERROR: ' + err);
} else {
var collection = db.collection('users');
// When login button run authUser function
$('#auth-btn').click(function () {
userInfo(db, function () {
db.close();
});
});
}
});
});
The problem is that when I click the button to auth the user in with correct info it returns a value of 'undefined' but without changing anything if I press the button a second time it returns the correct data from the database. I want it to display the first time round to properly authenticate the user in. What am I doing wrong ? please help.
You mean console.log(user_data); returns the undefined data?
That is because you are not calling it in the callback, so the first time the console.log(user_data); is called the db query did not find the user. When you call it the second time the first database query finished so user_data is already set so it will print it to you. Try looking up another user the second time you press the login button. It will print the first user's data.
Note that your calls are asynchronous! So in order to see the result of your query when it finishes just put the console.log(user_data); in the callback function passed into each.
Also if you want to limit your result set to only one element use db.collection.fidnOne({...}) instead of db.collection.find({...},{limit...}).each(...).

Promised Connections Returning Nothing (JS)

Problem with Promised Connections
I recently converted my Node app from running on my local machine to utilizing an Amazon EC2 for the Node app and a VPN for the file-serving and MySQL.
I learned just enough about Promises to write the following connection snippet (which runs 3 queries before responding to the client), utilizing Bluebird. The connections worked on my machine, but with the VPN hosted MySQL settings, the connections crashed every time, about 30 seconds after the app started, which I realized was probably because I'd forgotten to close them.
EDIT: Based on the comments, it appears the issue is not in the connection closures.
So I modified my script in the best way I knew to close the connections, but with Promises, this is confusing. This version of the connection doesn't work. It doesn't fail or cause any errors. It just returns no results on the server side. I think my problem is in the way I've closed the connections.
What's causing the issue?
Is it the connection closures?
If so, how would I close them properly?
My (Simplified) MySQL Connection Attempt with Bluebird Promises
var mysql = require('mysql');
var Promise = require('bluebird');
var moment = require('moment');
function createConnection() {
var connection = mysql.createConnection({
dateStrings : true,
host : 'hostname',
user : 'username',
password : 'password',
database : 'database'
});
connection = Promise.promisifyAll(connection);
return connection;
}
function sendGame(req, res, sales, settings, categories, players) {
var game = new Object();
game.sales = sales;
game.players = players;
game.settings = settings;
game.categories = categories;
var JSONgame = JSON.stringify(game);
console.log("Game: " + JSON.stringify(game, undefined, 4));
}
var retrieveSales = Promise.method(function (username, connection, timeFrame) {
console.log('User ' + username + ' retrieving sales...');
var q = 'select * from sales_entries where date BETWEEN ? AND ?';
return connection.queryAsync(q, timeFrame).then(function (results) {
return results[0];
});
});
var retrieveSettings = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving settings...');
var q = 'select * from sales_settings';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrieveCategories = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving categories...');
var q = 'select * from sales_categories';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrievePlayers = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving players...');
var q = 'select * from users';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var gameSucceed = Promise.method(function gameSucceed(req, res) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
//var connection = Promise.promisifyAll(createConnection());
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}).then(function () {
connection.end(),
console.log("...Connection with the MySQL database for Game retrieval ended")
});
});
function getGameData(req, res) {
gameSucceed(req, res).spread(function (sales, settings, categories, players) {
return sendGame(req, res, sales, settings, categories, players);
});
};
var req = new Object();
var res = new Object();
req.body = {
"username" : "user123",
"password" : "password"
}
getGameData(req, res);
Console Result
User user123 retrieving game...
Connection with the MySQL database openned for Game retrieval...
User user123 retrieving sales...
User user123 retrieving settings...
User user123 retrieving categories...
User user123 retrieving players...
...Connection with the MySQL database for Game retrieval ended
Game: {}
var gameSucceed = function gameSucceed(req, res) {
…
var connection = createConnection());
return connection.connectAsync().then(function () {
return Promise.all([…]);
}).then(function () {
connection.end();
});
};
The promise that is ultimately returned from this method does not have a resolution value. It is created by that then call from whose callback you do not return - which will lead to undefined. To fix this, just route the result through:
.then(function(results) {
connection.end();
return results;
});
However, if you do it like that the connection won't be closed in case of an error. The best solution is to use the finally() method, which just works like a finally clause in synchronous code. It's callback will be invoked both for resolutions and rejections, and the resulting promise will automatically carry on the value.
.finally(function() {
connection.end();
})
// .then(function(results) { })
Your code has a particular resource management problem like Bergi put it. You have to keep remembering when to close the collection and when not to.
The optimal solution would be to use Promise.using however, that's only available in the v2 branch of Bluebird so you're going to have to wait a while.
Until then, you can create your own wrapper method that does more basic scoped resource management:
function connect(fn,timeout){
timeout = (timeout === undefined) ? 8000 : timeout; // connection timeout
return createConnection().then(function(connection){
// run the function, when it resolves - close the connection
// set a 7 second timeout on the connection
return fn(connection).timeout(timeout).finally(function(){
connection.end();
});
});
}
Which would let you do:
connect(function(connection){
return gameSucceed(req,resp,connection); // connection is injected to that fn now
}).then(function(val){
// gameSucceed resolution value here
});
Now, when the gameSucceed is done, the connection will close itself automatically. This would make gameSucceed itself look like:
var gameSucceed = Promise.method(function gameSucceed(req, res,connection) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}); // no longer its responsibility to handle the connection
});
Generally, you might also want to consider a more OOPish style of coding for your code.
Good luck, and happy coding.

Processing database query in node.js

What's the correct way to process information from a database query after it has been retrieved.
Assuming the the below example that dataObj is just a js object that contains a field, name, which is defined, is this how I should be processing data in node.js?
EDIT:
forgot to mention that of course I can't return the data object because this is an async call.
function processData(dataObj){
if(dataObj.name == "CS"){
console.log("true");
}
}
function getData(anon)
var dat = .... sql query that works and its an object now that works correctly...
anon(dat);
}
getData(processData);
Here's a snippet of some code i'm working on using mongoose:
var db = mongoose.createConnection(uristring)
, mongoose = require('mongoose');
db.once('open', function(){
var recipientSchema = mongoose.Schema({
username: String,
recipientEmail: String
});
var Recipient = db.model('Recipient', recipientSchema);
Recipient.find( {username: user }, function(err, recipients){
res.json(recipients);
})
})
Hope that helps!
One of NodeJS' strengths is streaming support. I would expect from a proper SQL driver to give me one row at the time. If I want I can collect all of them, but most of the time I don't want all the rows in memory. Instead I would stream them one by one to a consumer.
My preferred DB code would look like...
var db = require('<somedriver>');
var sqlStatement = ".... sql query that works and its an object now that works correctly...";
var query = db.execute(sqlStatement);
query.on('row', function (row) {
// Do something with a row object...
console.log("This is a row", row);
});
query.on('done', function (err, rowcount) {
if (err) { throw err; } // or do something else...
console.log("Number of rows received", rowcount)
});
Hope this helps

Categories

Resources