I am attempting to get data from a mysql table using nodejs. I call the sql routine which is in another node js file. However, I cannot get my callback to return the data. I think the problem might be that I am calling an asynchronous routine from a node js file rather than from an angular or regular javascript program. Below is the exports script I am calling.
exports.getVenueById = function(db, id) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? "
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function(err, rows) {
if(err) console.log("error=" + err);
console.log("rows=" + rows[0]['auto_increment']);
res.json({success: true, response: rows});
//return rows[0];
});
}
I know this is working because I am writing the results to the console. The problem is the data never gets back to the calling node js routine below.
function getVenueData (id , callback) {
(function () {
venueData = venueTable.getVenueById(db, id);
if(venueData) {
callback();
console.log("callback in loop");
}
console.log("callback after loop");
});
}
getVenueData(id, gotVenueData);
The program immediately returns and displays the timeout message. I admit that I am not an expert in nodejs or its callback feature. I would appreciate any feedback as to how I can get the program to wait for the asynchronous data to return to the calling program.
function gotVenueData() {
console.log("gotVenueData");
}
setTimeout(function() { console.log("timeout for 10 seconds");} , 10000);
console.log("venuedata=" + venueData);
You're trying to return async data syncronously. Instead, add a callback to getVenueById:
exports.getVenueById = function (db, id, cb) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? ";
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function (err, rows) {
if (err) console.log("error=" + err);
console.log("rows=" + rows[0]['auto_increment']);
cb({
success: true,
response: rows
});
// return rows[0];
});
and use it as such:
venueTable.getVenueById(db, id, function(data) {
console.log(data);
});
One caveat: Traditionally the callback has the first parameter as the error (or null) and then the actual data. With that in mind:
exports.getVenueById = function (db, id, cb) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? ";
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function (err, rows) {
if (err) { cb(err); }
console.log("rows=" + rows[0]['auto_increment']);
cb(null, {
success: true,
response: rows
});
// return rows[0];
});
and use it as such:
venueTable.getVenueById(db, id, function(err, data) {
if (err) { return console.log(err); }
console.log(data);
});
Related
I have an own database of Youtube videos. What it contains so far is the id of these certain videos; the one which can be found in the video link as well.
I'm looking for a method that I can use to insert both the title and the description of them into the database by the use of the Youtube API and MySQL.
By the use of the mysql npm, I could connect to the database, but the async nature confuses me a bit.
Here's my original (incomplete) code:
var request = require('request');
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : (this is secret)
database : 'video_db'
});
connection.query('SELECT id FROM videos', function(err, rows, fields) {
if (err) throw err;
for(i=0;i<rows.length-1;i++){
var APIkey = (this is also secret)
var videoid = rows[i].id;
//gets data of a single video
var API_URL = 'https://www.googleapis.com/youtube/v3/videos'
+ '?part=snippet'
+ '&id=' + videoid
+ '&key=' + APIkey;
request(API_URL, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(JSON.parse(body));
} else {
console.log(error);
};
});
};
});
Questions:
1.) To make it work, another connection.query would be necessary within the request, but since that also works asynchronously, I'm quite unsure about the outcome. What is the proper way to write elements of that response into the database? Should I use another kind of apporach? Is it possible that writing the whole logic within 'SELECT id FROM videos' was a bad idea?
2.) I tried the API links and they worked in the browser, but when the code itself runs, request throws and error, which consists of the following message:
{ [Error: connect ENOBUFS 216.58.214.202:443 - Local (undefined:undefined)]
code: 'ENOBUFS',
errno: 'ENOBUFS',
syscall: 'connect',
address: '216.58.214.202',
port: 443 }
What's the source of this problem? (if it's viable to be another question on its own, I'm willing to remove from the original question, as this is less of the part of the original issue)
Make Your query safe: add "ORDER BY id DESC LIMIT 10" to Your query. Otherwise it reads all records from table.
You're sending too many requests inside of for loop so You're wasting memory for requests (no buffers error) without waiting for one to finish.
Better to do it like this:
var request = require('request');
var mysql = require('mysql');
var async = require ('async');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'this is secret',
database : 'video_db'
});
var APIkey = "SECRET KEY";
var apiUrls = [];
connection.query('SELECT id FROM videos ORDER id LIMIT 10', function(err, rows, ) {
if (err) throw err;
rows.forEach(function(row){
var API_URL = 'https://www.googleapis.com/youtube/v3/videos'
+ '?part=snippet'
+ '&id=' + row.id
+ '&key=' + APIkey;
apiUrls.push(API_URL);
};
});
async.eachSeries(apiUrls, function(apiUrl, next){
request(apiUrl, function (error, response, body) {
if(error || response.statusCode != 200) {
console.error(response.statusCode, error);
return next();
}
console.log(JSON.parse(body));
next();
});
});
OR if You insist to loop all of records:
var request = require('request');
var mysql = require('mysql');
var async = require ('async');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'this is secret',
database : 'video_db'
});
var APIkey = "SECRET KEY";
connection.query('SELECT id FROM videos', function(err, rows) {
if (err) throw err;
async.eachSeries(rows, function(row, next){
//gets data of a single video
var apiUrl = 'https://www.googleapis.com/youtube/v3/videos'
+ '?part=snippet'
+ '&id=' + row.id
+ '&key=' + APIkey;
request(apiUrl, function (error, response, body) {
if(error || response.statusCode != 200) {
console.error(response.statusCode, error);
return next();
}
console.log(JSON.parse(body));
next();
});
};
});
I am trying to write a Cloud Code function that will allow me to edit the data of another user as I cannot do that in the application it self. What the code does (I should say tries to do as I don't know JS) is fetch a User object and a Group (a class I created) object using two separate queries based on the two object IDs inputed. Here is my code
Parse.Cloud.define("addInvite", function(request, response) {
Parse.Cloud.useMasterKey();
var userID = request.params.user;
var groupID = request.params.group;
var user;
var group;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userID);
return userQuery.first
({
success: function(userRetrieved)
{
user = userRetrieved;
},
error: function(error)
{
response.error(error.message);
}
});
var groupObject = Parse.Object.extend("Group");
var groupQuery = new Parse.Query(groupObject);
groupQuery.equalTo("objectId", groupID);
return groupQuery.first
({
success: function(groupRetrieved)
{
group = groupRetrieved;
},
error: function(error)
{
response.error(error.message);
}
});
var relations = user.relation("invited");
relations.add(group);
user.save();
response.success();
});
Every time I execute the method I get the error:
[Error]: success/error was not called (Code: 141, Version: 1.9.0)
Can anyone help with this? Thanks.
Every function in Parse Cloud returns a Promise. This also includes any query functions which you run to retrieve some data. Clearly in your code you are returning a Promise when you execute a query which abruptly ends your cloud function when your query completes. As you do not call a response.success() or response.error() in any of the success blocks, your cloud function returns without setting a suitable response, something that Parse requires and hence the error. Your code needs to chain all the promises to ensure your code is executed correctly and return success/error in the last step:
Parse.Cloud.define("addInvite", function(request, response) {
Parse.Cloud.useMasterKey();
var userID = request.params.user;
var groupID = request.params.group;
var user;
var group;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userID);
userQuery.first().then(function(userRetrieved) {
user = userRetrieved;
var groupObject = Parse.Object.extend("Group");
var groupQuery = new Parse.Query(groupObject);
groupQuery.equalTo("objectId", groupID);
return groupQuery.first();
}).then( function(groupRetrieved) {
//group = groupRetrieved;
var relations = user.relation("invited");
relations.add(groupRetrieved);
return user.save();
}).then(function() {
response.success();
}, function(error) {
response.error(error.message);
});
});
I am having issues getting node to make a database call without proceeding despite the database function has not returned a value.
Here is the basic http server code:
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-origin': '*' // implementation of CORS
});
response.end("ok");
;
}).listen(8080,'0.0.0.0');
Using the request.on('data') function, I am able to decode JSON from requests and proceed that to make a database call:
request.on('data', function (chunk) {
var json = JSON.parse(chunk);
var id = parseInt(json["id"]);
response.end(callDatabase(id));
});
The database function goes something like this:
function callDatabase(id) {
var result;
var connection = mysql.createConnection(
{
host : '192.168.1.14',
user : 'root',
password : '',
database : 'test'
}
);
connection.connect();
var queryString = 'SELECT name FROM test WHERE id = 1';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
result = rows[i].name;
}
});
connection.end();
return result;
}
}
However under testing, this proves that I am doing it wrong. I am aware that I probably want to be using the node asynchronous module, which I have tired. I have also tried using the waterfall method, as well as parallel and many other tutorials online. I feel that the request.on function should be in parallel, then the database call async, so whilst node is waiting for the response from the database server, it is free to get on with any other requests, leaving the queued time to a minimum.
Please inform me if I have miss-understood any of the concepts of node js.
You are returning result and closing the connection before the query has returned it's value from the db. Place that code inside the callback.
Fixing your code, it should look like this:
function callDatabase(id) {
var result;
var connection = mysql.createConnection(
{
host : '192.168.1.14',
user : 'root',
password : '',
database : 'test'
}
);
connection.connect();
var queryString = 'SELECT name FROM test WHERE id = 1';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
result = rows[i].name;
}
connection.end();
return result;
});
}
Although, this will only solve part of the problem, since now you're still calling response.end(callDatabase(id)); before waiting for a response from the query.
In order to fix this, you need to return some kind of callback.
function callDatabase(id, callback) {
// the method code here...
connection.query(queryString, function(err, rows, fields) {
// code...
// instead of returning the result, invoke the callback!
callback(rows);
});
}
Now you can call it like this :
request.on('data', function (chunk) {
var json = JSON.parse(chunk);
var id = parseInt(json["id"]);
callDatabase(id, function(res) {
response.end(res);
});
});
I have this code running in my parse cloud, and when I call it form my app, it never enters the success or error statement. Probably because the .save does not work?
Any help is much appreciated :)
This is how I call the cloud function :
[PFCloud callFunctionInBackground:#"addFeeling"
withParameters:#{#"userId" : [[PFUser currentUser]objectId],
#"relationShipId" : _friendship.objectId,
#"tagId" : [NSNumber numberWithInt:tag],
#"reason" : #"Hardcoded HomeView(409)",
#"value" : [NSNumber numberWithInt:value]}
block:^(NSString *result, NSError *error) {
if (!error) {
DLog(#"results :%#", result);
}
else{
DLog(#"Error : %#", error);
}
}];
And this is the cloud fucntion itself:
Parse.Cloud.define("addFeeling", function(request, response) {
var userId = request.params.userId;
var relationShipId = request.params.friendshipId;
var tagId = request.params.tagId;
var reason = request.params.reason;
var value = request.params.value;
var Feels = Parse.Object.extend("Feels");
var feeling = new Feels();
feeling.set("id_friendship", relationShipId);
feeling.set("value", value);
feeling.set("tag", tagId);
feeling.set("reason", reason);
feeling.save({
success: function () {
var query = new Parse.Query("Feels");
query.equalTo("id_friendship", relationShipId);
query.find({
success: function(results) {
if(results.length > 0)
{
result = results[0];
if(result.get("userFrom") == userId)
result.set("scoreTo" , result.get("scoreTo") + value);
else
result.set("scoreFrom", result.get("scoreFrom") + value);
result.save();
}
}
});
console.log("Save ok");
},
error: function (error) {
response.error(error);
console.log("Save ko");
}
});
});
This is probably really simple but I'm just not used to JS at all.
The error i get is code:141, enver entering success/error.
When your function is finished with doing what you intend it to do, you are supposed to call either response.success() or response.error() to indicate that you are done.
You are already doing it for the case there is an error, but not when actually processing the result of your query.
I have an application in windows phone and make registration with facebook and I store some data in a table, however, a single user it is being stored more than once in the table. I tried (getting the fb-id) check on the table if a record with that fb-id, but before re registrare l new user should check whether there is, however, such as asynchronous methods there is no order and always first executes the query insertion, as I can resolve this?
client side (limited)
await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.Facebook);
Message = string.Format("User Authenticate - {0}", App.MobileService.CurrentUser.UserId);
//***** Get fb info
var userId = App.MobileService.CurrentUser.UserId;
var facebookId = userId.Substring(userId.IndexOf(':') + 1);
var client = new HttpClient();
var fbUser = await client.GetAsync("https://graph.facebook.com/" + facebookId);
var response = await fbUser.Content.ReadAsStringAsync();
var jo = JObject.Parse(response);
var FbidUser = jo.GetValue("id");
var userName = jo.GetValue("name");
var genero = jo.GetValue("gender");
but, i slould be do at server client, but how to insert info data one time, i mean, Check the record in the table before inserting.
Server side Azure:
function insert(item, user, request)
{
item.UserName = "<unknown>"; // default
var identities = user.getIdentities();
var req = require('request');
if (identities.facebook)
{
var fbAccessToken = identities.facebook.accessToken;
var url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
req(url, function (err, resp, body)
{
if (err || resp.statusCode !== 200)
{
console.error('Error sending data to FB Graph API: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
}
else
{
try
{
var userData = JSON.parse(body);
item.UserName = userData.name;
request.execute();
} catch (ex)
{
console.error('Error parsing response from FB Graph API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
});
}
}
according to the above code, i have a second question, in the developer center on facebook, I have access to email and photos (my application), I guess userData variable contains this information?, how do I access it?, how to call those properties where the rest of the information?
If all you want is to prevent two items for users with the same name to be inserted, the easiest way would be to not use the name at all, but instead use the FB id (after all, it's possible that two different people have the same name). That you can do with the script below:
function insert(item, user, request)
{
item.UserId = user.userId;
var currentTable = tables.current;
currentTable.where({ UserId: user.userId }).read({
success: function(results) {
if (results.length > 0) {
// an item with that user id already exists in the table
request.respond(400,
{ error: 'item already in the table' });
} else {
// new user, can insert it here
request.execute();
}
}
});
}
Now, if you really want to use the user name as the "key" for your table, you can do something similar as well:
function insert(item, user, request)
{
item.UserName = "<unknown>"; // default
var identities = user.getIdentities();
var req = require('request');
var currentTable = tables.current;
if (identities.facebook)
{
var fbAccessToken = identities.facebook.accessToken;
var url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
req(url, function (err, resp, body)
{
if (err || resp.statusCode !== 200)
{
console.error('Error sending data to FB Graph API: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
item.UserName = userData.name;
currentTable.where({ UserName: item.UserName }).read({
success: function(results) {
if (results.length > 0) {
request.respond(statusCodes.BAD_REQUEST,
{ error: 'Name already in the table' });
} else {
request.execute();
}
}
});
} catch (ex) {
console.error('Error parsing response from FB Graph API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
});
}
}