mysql and socket interaction in node.js - javascript

I'm writing a simple online videogame with node js and I want to manage the score of each player saving it in a database(mysql).
Now in the server side I have a piece of code like this:
socket.on('game_over',function(data){
for (var i = 0; i < players.length; i++) {
if(players[i].id == data.id){
var sql;
sql='UPDATE login SET email=? WHERE username=?'
connection.query(sql, [data.score,"d"],function(error, results, fields) {
console.log(sql);
console.log(error);
if (error) throw error;
console.log(result);
});
players.splice(i,1);
break;
}
}
socket.broadcast.emit('p_disconnect',data.id);
});
When I start my server and a game_over signal is recived, my server disconnect.
The print of the sql query is correct and I don't see any error since it return me 'null'
Why my server disconnect after that, and more importantly what can I do to keep the server up?
Without the connection.query part it works like it should

Based on the comment on the question:
// assuming
const players = [
{id: 1, otherInfo: 'foobar' },
{id: 2, otherInfo: 'foobar' },
]
const connection = mysql.connect() // something like this
// When the game ends we assume that the game_over event is fired
socket.on('game_over',function (data) {
// "I need to find the correct player"
const correctPlayer = players.find(player => player.id === data.id)
// "and delete it from the list of the active players"
const position = players.indexOf(correctPlayer)
players.splice(position, 1)
// "and update the database with it's score" => depends on your DB structure
const query = `UPDATE youTable SET score = ${data.score} WHERE playerId = ${correctPlayer.id}`
// here depends on how you want to manage the query result (some examples)
// run query (is async cause how js works) and just log the result
connection.query(sql, function(error, results, fields) {
// this code is executed when the query ends
console.log(error, results, fields)
}
// this code is executed after starting the query
socket.broadcast.emit('p_disconnect', data.id);
// run query and emit event after the query ends
connection.query(sql, function(error, results, fields) {
socket.broadcast.emit('p_disconnect', data.id);
console.log(error, results, fields)
}
});

Related

Variable undefined nodeJS MySQL query

I have a table with different post categories and I want to get the categories ID from the name. Example name: random => id: 1.
I got the variable like this:
const { name, title, cat, con, user_file } = req.body;
console.log(cat); //returnes the name as it should
This is my query:
var sql = "SELECT id FROM cat WHERE cat_name = ?";
db.query(sql, cat, function(err, result) {
if(!result){
return next();
}
const cat_id = result[0];
});
If I than try to console.log the cat_id I get undefined. I have tried doing this in many different way but it comes out the same every time. If I just run
SELECT id FROM cat WHERE cat_name = random
in thee database manager it works like it should and returnes the ID.
Edit: The purpose is to get the id to insert a foreign key into another table.
Your results is an empty array. This is (assuming you're using the mysql package) because your function call is incorrect.
When passing arguments to your query, as explained here, you need to pass an array of values, not just a single value. For example:
connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
In your case, that means you're looking for cats where the name is the first character of cat (e.g. cat[0]).
It ended up being a problem with variables only being saved in the query level. It console.logged the right number inside the db.query and the wrong one out of the db.query. So the solution for now is to put it inside I guess.
My solution now looks like this:
exports.post = (req, res, next) => {
let { cat } = req.body;
let cat_id = 0;
db.query(
"SELECT id FROM cat WHERE cat_name = ?",
[cat],
async function (err, results) {
if (!err) cat_id = results[0].id;
else console.log(err);
db.query(
"INSERT INTO posts SET ?",
{ cat_id: cat_id },
(error, results) => {
if (error) console.log(error);
else res.status(200).redirect("/post");
}
);
}
);
};

How to obtain the value of the result in a `node-mysql` query

I am weighting a node.js application, the result I get from my mysql query is,
[ RowDataPacket { name: 'ubuntu' } ]
(Ubuntu is the only thing in the row)
What I would like to do is shorten my variable, "results" so that it equals ubuntu for example, or just every thing between the '', I am new to JS. I am using the standard way of querying the sql database,
It is being done as so:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root', //just using root for my personal testing.
password : 'root',
database : 'Sonic'
});
connection.connect();
var connect = connection.query( 'SELECT name FROM Sonic_url',
function(err, fields, results, rows) {
// if (results === input) {
var sqldata = results.substring(1, 4);
console.log(results);
if (err) throw err;
// console.log('I belive we have found what you are after, is: ' + input + ' ' + 'what you are after?');
//}
});
I would like to be able to do a basic IF with the variable input and a variable from the mysql query, so I can print to screen if the result was found or not.
The correct signature for the mysql query is:
connection.query(query, function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
What you want is to log the value of name. If your query produces one result, you can access this value from the first item in the rows array:
connection.query('SELECT name FROM Sonic_url', function(err, rows, fields) {
console.log(rows[0].name);
});

Sails.js: Nested MongoDB queries

I am using Sails v0.11 and am developing an standalone importer script in order to import data to mongoDB and - that is now the not-working part - build the associations between the models.
For this process I introduced temporary helper properties in the models in order to find the associated records and replace them by in real MongoDB _ids.
The script starts Sails in order to be able use its features (waterline, etc.):
var app = Sails();
app.load({
hooks: { grunt: false },
log: { level: 'warn' }
}, function sailsReady(err){
processUsers() finds all users and their _ids and iterates over them to invoke a second function addOrgsToOneUser()
var processUsers = function() {
// Iterate through all users in order to retrieve their _ids and
app.models['user'].native(function(err, collection) {
collection.find({}, projectionOrgInUser).toArray(function (err, users) {
Async.eachSeries(users, function (user, next){
// prepare userInOrgs
whereUserInOrg = { orgId: { $in: userInOrgs } };
//This is invoking
addOrgsToOneUser(user, whereUserInOrg);
next();
}, function afterwards (err) {
if (err) {
console.error('Import failed, error details:\n',err);
return process.exit(1);
}
console.log("done");
return process.exit(0); // This returns too early, not executing the addOrgsToOneUser
});
});
});
};
addOrgsToOneUser() finds all orgs belonging to THIS user and updates then the orgs array property of THIS user
var addOrgsToOneUser = function(user, whereUserInOrg) {
var projectionUserInOrg = "...";
// Find all orgs that this user is associated to and store it in inOrgs
app.models['org'].native(function(err, collection) {
collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) {
// prepare inOrgs which is needed for updating
//update user to have an updated orgs array based on inOrgs.
app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){
console.log('Updated user ' + user._id.toString() + ' to be in their orgs');
});
});
});
}
Problem:
Process.exit(0) is called before the query/update of saddOrgsToOneUser() has completed. It behaves as expected if saddOrgsToOneUser() contains just a console.log for instance, but queries are triggered ansynchronously of course.
In case I comment out Process.exit(0), the script never stops, but the queries are executed as intented.
As the script will have further nested queries, I need a better approach to this as manually kill this script ...
How is nesting queries and iterating over their results done properly?
Thank you very much,
Manuel
addOrgsToOneUser is asynchronous. next() needs to be called after everything is done inside addOrgsToOneUser. The way I would do it is to pass in a callback (next) and call it when everything is done. So the call is
addOrgsToOneUser(user, whereUserInOrg, next);
and the addOrgsToOneUser will have an extra argument:
var addOrgsToOneUser = function(user, whereUserInOrg, callback) {
var projectionUserInOrg = "...";
// Find all orgs that this user is associated to and store it in inOrgs
app.models['org'].native(function(err, collection) {
collection.find(whereUserInOrg, projectionUserInOrg).toArray(function (err, orgs) {
// prepare inOrgs which is needed for updating
//update user to have an updated orgs array based on inOrgs.
app.models['user'].update({'id' : user._id.toString()}, {'orgs': inOrgs}).exec(function afterwards(err, updated){
console.log('Updated user ' + user._id.toString() + ' to be in their orgs');
callback(); // your original next() is called here
});
});
});
}

How to elegantly detect when all mongo inserts have completed

Ive written and basic Node app (my first) to insert many csv rows into mongo (items array in the code below). Once all items have been inserted the db connection should be closed and the program exited.
The issue ive been working with is figuring out when to close the db connection once all inserts have returned a result. Ive gotten it working by counting all of the insert result callbacks but to me this feels clunky. I know one improvement I could make is to batch the inserts via an array to the insert function but ill still need to have my code be aware of when all inserts have completed (assuming it would be bad to insert 100k items in one query). Is there and better way (my code feels hacky) to do this?
Hack part...
function (err, result) {
queryCompletedCount++;
if (err) console.log(err);
//Not sure about doing it this way
//Close db once all queries have returned a result
if (queryCompletedCount === items.length) {
db.close();
console.log("Finish inserting data: " + new Date());
}
}
Full insert code
MongoClient.connect(dbConnectionURL, function (err, db) {
if (err) {
console.log("Error connecting to DB: " + err);
} else {
var productCollection = db.collection('products');
console.log("Connected to DB");
console.log("Start inserting data: " + new Date());
var queryCompletedCount = 0;
for (var i = 0; i < items.length; i++) {
productCollection.insert([{
manufacturerCode: null,
name: items[i].name,
description: null
}], function (err, result) {
queryCompletedCount++;
if (err) console.log(err);
//Not sure about doing it this way
//Close db once all queries have returned a result
if (queryCompletedCount === items.length) {
db.close();
console.log("Finish inserting data: " + new Date());
}
});
}
}
});
What do you think about realizing this issue with async module like this:
async = require('async')
async.eachSeries(items, function (item, next) {
productCollection.insert(productCollection.insert(
[{
manufacturerCode: null,
name: item.name,
description: null
}], function (err, result) {
if (err) {
return next(err);
}
next();
})
)
}, function () {
// this will be called after all insertion completed
db.close();
console.log("Finish inserting data: " + new Date());
});
What you need here is MongoDB's Write Concern, configured in the strictest way.
There are two levels of Write Concern. The first is the write mode, in which case the query returns only if the result is written to the configured number of mongo instances. In your case I suppose there is a single instance, but for future you may configure it as "w": "majority". The second level is the Journal concern, where by setting "j": 1 your query will return only when the data is written into the journal.
So in your case you best Write Concern configuration might be {"w": "majority", "j": 1}. Just add it as the last argument of your insert statement.

Sqlite: check if database exist

I am developing a mobile application using phonegap that store some data into the local database (sqlite DB).
I need to know if the database exist or not, and that to determine which process need to execute.
var database = window.openDatabase("my_db", "1.0", "sample DB", 30000);
if (check_db_exist()) {
process_1();
}
else
{
process_2();
}
I needed to do something similar, I needed to check if the application had a db already created (legacy DB) and if so export all the data to the new db (new and improved DB) and then delete this DB.
Background Info: I was moving from simple keyvalue tables to complex relational DB with cascades etc.
function onDeviceReady() {
// CHECK IF LEGACY DATABASE EXISTS. IF DOES EXPORT EXISTING DATA TO NEW DB THEN DELETE LEGACY
window.resolveLocalFileSystemURL(cordova.file.applicationStorageDirectory + "/databases/<DatabaseName>.db", exportToNewDB, setupDB);
}
Note: If file exists (success), then we need to do our export code in here, then delete file so this method will always fail. If file doesn't exist - user has already exported to new DB or they our new user and never had legacy DB.
// Fail Method
function setupDB() {
newDB = window.sqlitePlugin.openDatabase({ name: "<NewImprovedDBName>.db" });
newDB.transaction(sql.initDB, sql.errorCallback, sql.successCallBack);
}
// Success Method
function exportToNewDB() {
db = window.sqlitePlugin.openDatabase({ name: "<LegacyDBName>.db" });
db.transaction(function (tx) {
setupDB();
// Insert Export code Here
// Delete DB
window.sqlitePlugin.deleteDatabase("<LegacyDBName>.db", sqlSuccess, sqlFail);
}, sqlFail);
}
Answer to your Question:
window.resolveLocalFileSystemURL(cordova.file.applicationStorageDirectory + "/databases/my_db.db", process_1, process_2);
The best way for determining if the DB exists or not is to check if the file that represents it exists. This is a simple IO operation, like the following example:
string path = Path.Combine(ApplicationData.Current.LocalFolder.Path, databaseName);
if (File.Exists(path))
{
//your code here
}
I don't think that you can check for the existence of the DB directly. I've researched and haven't found a way to do it using a simple function call. However, this seems to be a popular request, and here's a workaround:
var db = window.openDatabase("my.db", "1", "Demo", -1);
db.transaction(function (tx) {
/*I don't think that there is a way to check if a database exists.
As I think that the openDatabase call above will just create
a missing DB. Here is a second-best way to do it - there
is a way to check to see if a table exists. Just pick a table that
your DB should have and query it. If you get an ERROR, then you
can assume your DB is missing and you will need to create it. */
console.log("Trying to get the test data");
tx.executeSql("select * from test_table", [], function (tx, res) {
var len = res.rows.length, i;
for (i = 0; i < len; i++) {
console.log(res.rows.item(i).data);
}
}, function (err) {
console.log("Error selecting: " + err);
//NOW we need to create the DB and populate it
tx.executeSql('CREATE TABLE IF NOT EXISTS test_table (id integer primary key, data text)');
tx.executeSql('INSERT INTO test_table (data) VALUES("test data one")');
tx.executeSql('INSERT INTO test_table (data) VALUES("test data two")');
//now test select
tx.executeSql("select * from test_table", [], function (tx, res) {
var len = res.rows.length, i;
for (i = 0; i < len; i++) {
console.log(res.rows.item(i).data);
}
});
//now clean up so we can test this again
tx.executeSql('DROP TABLE IF EXISTS test_table', [], function (tx, res) {
console.log("dropped table");
}, function (err) {
console.log("Error dropping table: " + err);
});
});
});
As you can see, the error function during the first query will create and populate the DB. It's using exception handling for program logic flow, but it works!

Categories