Same value keeps appearing in Javascript callback - javascript

I have the following bit of code in Node.js.
function homeCallback(reply, twid) {
var c = reply.length;
for (var i = c - 1; i >= 0; i--) {
var isRT;
var tweet_id;
if (reply[i].hasOwnProperty('retweeted_status')) {
tweet_id = reply[i].retweeted_status.id_str;
isRT = true;
} else {
tweet_id = reply[i].id_str;
isRT = false;
}
console.log(tweet_id);
var existsQ = "SELECT * FROM tweets WHERE tweet_id=" + connection.escape(tweet_id);
connection.query(existsQ, function (err, rows) {
console.log(tweet_id);
//need to use tweet_id here
});
}
}
reply is a json response from a call to stauses/home_timeline of Twitter's API, connection is a mysql connection
If there are a couple of tweets in reply with ids of 11 and 12 I get an output like this:
11
12
12
12
Although I expect an output like this:
11
12
11
12

The callback on connection.query() would execute asynchronously while local variable tweet_id scoped in the for-loop might get overwritten by next iteration.
Try to duplicate tweet_id inside a closure/function call.
(function(tid) {
console.log(tid);
var existsQ = "SELECT * FROM tweets WHERE tweet_id=" + connection.escape(tid);
connection.query(existsQ, function (err, rows) {
console.log(tid);
//need to use tweet_id here
});
})(tweet_id);
This is not ideal, but would give you some idea.

Related

Getting User Activity Reports for a given list of users in G Suite

I'm trying to use the Admin SDK Reports Service to get the last login time and some other data for 20 users. It's not feasible to get the data for the whole domain and then filter down due to the size of the domain, so I want to get the data for only these 20 users, but I can't seem to find a way to do that. My current code fails with Admin user usage reports get failed with error: GoogleJsonResponseException: API call to reports.userUsageReport.get failed with error: Bad Request
I know this is wrong but looking at the docs I'm not sure what to do. I can use one user and that works fine on the website, but it seems weird that the only option would be to get all users or one user. I tried to modify my code to get one user multiple times in a loop, but fails with the above error. the userList value is pulled from a table in the AppMaker user interface. I can also use the documentation website's API explorer with no problems.
Here's my current function:
function generateLoginActivityReport(userList) {
var today = new Date();
var oneWeekAgo = new Date(today.getTime() - (7 * 24 * 60 * 60 * 1000));
var timezone = Session.getScriptTimeZone();
var date = Utilities.formatDate(oneWeekAgo, timezone, 'yyyy-MM-dd');
userList = JSON.parse(userList);
//console.log("server code: " + list);
for (var a = 0; a < userList.length; a++) {
//console.log(userList[a]);
var parameters = [
'accounts:last_login_time',
'drive:num_items_created'
];
var rows = [];
var pageToken;
var page;
do {
page = AdminReports.UserUsageReport.get('all', date, {
parameters: parameters.join(','),
maxResults: 1,
pageToken: pageToken,
userKey: userList[a]
});
var reports = page.usageReports;
if (page.warnings) {
for (var q = 0; q < page.warnings.length; q++) {
var warning = page.warnings[a];
Logger.log(warning.message);
}
}
if (reports) {
for (var i = 0; i < reports.length; i++) {
var report = reports[i];
try {
var parameterValues = getParameterValues(report.parameters);
var row = [
report.date,
report.entity.userEmail,
parameterValues['accounts:last_login_time'],
//parameterValues['drive:num_items_created']
];
rows.push(row);
var ar = app.models.ActivityReport.newRecord();
ar.LastLogin = parameterValues['accounts:last_login_time'];
console.log(report.entity.userEmail);
ar.DocsAdded = 0; //getting this value is another issue but unrelated so it's set to 0 for now.
ar.Email = report.entity.userEmail.toString();
app.saveRecords([ar]);
}
catch(error) {
console.error("Error! Did not write last item to model: \n"+error);
}
}
}
} while (pageToken);
}
}
The problem is caused by the way how you call the method AdminReports.UserUsageReport().
The right syntax is:
AdminReports.UserUsageReport.get(userKey, date, optionalArgs)
Thus, you need to substitute the userkey ‘all’ through userList[a], rather than inserting the userkey in the parameters:
page = AdminReports.UserUsageReport.get(userList[a], date, {
parameters: parameters.join(','),
maxResults: 1,
pageToken: pageToken,
});

JavaScript Anonymous function in function behaves strangely [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am doing simple app in javascript. I have "main_script" where I invoke everything. There is global variable "feeds" which is an array, like this:
var feeds = [];
Then after that I use function, that loads JSON file from multipe URLs (also array):
feeds = LoadJsonFeeds(urls); // Load feeds
console.log("main_code feeds.length: " + feeds.length);
That console log I mention later. Ok and now he is my LoadJsonFeeds (in different .js file, just a function):
function LoadJsonFeeds(urls) {
var feeds_tmp = [];
// URLs can be more - for example 50 feeds from url[0] and 20 from url[1]
for(var u = 0; u < url.length; u++) {
$.getJSON(url[u], function(data) {
var allFeeds = data.Result.Items; // allFeeds without check if they are ok
for(var i = 0; i < allFeeds.length; i++) {
// Is feed ok?
if (allFeeds[i].Text != null)
{
// Some more checking, but lets say ok for this
feeds_tmp.push(allFeeds[i]);
}
// This I mention later
console.log("LoadJson feeds.length: " + feeds.length);
}
});
}
console.log("LoadJson return"); // Mention later
return feeds_tmp;
}
And here is the problem I am struggling with. When I look at the console, here what I see:
LoadJson return
main_code feeds.length: 0
LoadJson feeds.length: 1
LoadJson feeds.length: 2
LoadJson feeds.length: 3
etc...
I just don't see the logic behind it! How can it first returned the function with nothing, then the main_script continues. After that, the function ALTER one by one the global variable "feeds". I suspect the anonymous function, but don't know what to do with it.
What am I trying to achive? Simple, I wanted to have function, that load JSON files from URLs. For example url[0] has 50 feeds, url[1] has 20. If everything is ok then it should return array of 70 feeds. I use this for the first time in main_script, and then in interval for update, which I call every few seconds. In this function I check, which feed is new and put it somewhere else:
function UpdateFeeds(url) {
console.log("updating...");
var feeds_tmp = LoadJsonFeeds(url);
console.log("Update feeds_tmp.length: " + feeds_tmp.length); // This is 0
for(var f_tmp = 0; f_tmp < feeds_tmp.length; f_tmp++) { // This does not happen because feeds_tmp.length = 0
for(var f = 0; f < feeds.length; f++) {
// Check what feed is new and put it somewhere else (the new one)
}
}
}
feeds = feeds_tmp; // Make all new feeds the global variable
}
But since the returned array is 0, that forloop does not happen. But it will still alter the global variable "feeds" anyway. For the main function it does not matter. In global variable the datas are in it, but I really need to find a new ones and do some work with it. But since it does not work that way, I am pretty lost.
What am I missing and how to fix this? Thank you!
Your console.log("LoadJson feeds.length: " + feeds.length); called later because its a asynchronous call , you can update this function as
function LoadJsonFeeds(urls,callback) {
var feeds_tmp = [];
// URLs can be more - for example 50 feeds from url[0] and 20 from url[1]
for(var u = 0; u < url.length; u++) {
$.getJSON(url[u], function(data) {
var allFeeds = data.Result.Items; // allFeeds without check if they are ok
for(var i = 0; i < allFeeds.length; i++) {
// Is feed ok?
if (allFeeds[i].Text != null)
{
// Some more checking, but lets say ok for this
feeds_tmp.push(allFeeds[i]);
}
// This I mention later
console.log("LoadJson feeds.length: " + feeds.length);
}
if(u==url.length.1) // to make sure all URL loaded
callback(feeds_tmp)
});
}
}
And call your function as
feeds = LoadJsonFeeds(urls,function(feeds){
console.log("main_code feeds.length: " + feeds.length);
}); // Load feeds

I am getting back the index # and "undefined" from these if/for loops

So I am looking in my database right now and there is 3 articles, so the x should represent the number 3 for the for loop later. This code is supposed to add articles to the database if they are freshly scraped. In the titles[] array there is 100 items (scraped from news.google). When I execute the code, it seems like it correctly finds the index # of the titles[] list (which is the 55,68,60 repeats), but it shows up as this: (I don't even want the index # being displayed in console either, I want the title of article to be displayed. I had to shrink some of this code, too long)
55
68
60
55
68
60
55
68
60
55
68
60
55
68
60
55
68
Complete.
Successfully added article: undefinedto the database.
Successfully added article: undefinedto the database.
Successfully added article: undefinedto the database.
Successfully added article: undefinedto the database.
Successfully added article: undefinedto the database.
Successfully added article: undefinedto the database.
And here is my code:
// accessing the database
function DatabaseTime(sourcesDates, timeAdded, links, titles, descriptions) {
sourcesDates = sourcesDates;
links = links;
titles = titles;
descriptions = descriptions;
// put counter so params can access this in it's object scope, use it for the for-loop
// object operator. MEAT OF THE BURGER
var databaseOperation = function (sourcesDates, timeAdded, links, titles, descriptions) {
var scanParams = { TableName: "Rnews" }
// using code to setup for accessing the 2nd list
db.scan(scanParams, function(err, scanData) { // scanData = the 2nd list we are going to work with
//use this array later to hold the unique items
var arrayCheck = [];
for (let i = 0; i < scanData.Items.length; i++) {
arrayCheck.push(scanData.Items[i].title);
}
var index = 0;
var counter = 0;
var x;
for (var i = 0; i < titles.length; i++) {
index = 0;
x = 0;
for (var x = 0; x < arrayCheck.length; x++) {
//if (titles[i] === arrayCheck[x]) {
if (titles.indexOf(arrayCheck[x] === -1)) {
index = titles.indexOf(arrayCheck[x]);
console.log(index);
var autoParams = {
TableName: "Rnews",
Item: {
title: titles[index],
source: sourcesDates[index],
url: links[index],
description: descriptions[index],
lastAddOrUpdated: dbTimeStamp,
timePublish: timeAdded[index]
}
}
Insert(autoParams, titles);
}
}
}
function Insert(autoParams) {
db.put(autoParams, function(err, data) {
if (err) throw err;
console.log("Successfully added article: " + titles[i] + "to the database.");
});
}
console.log("Complete.");
});
};
databaseOperation(sourcesDates, timeAdded, links, titles, descriptions);
}
//// END
DatabaseTime(sourcesDates, timeAdded, links, titles, descriptions);
(printing the index):
You're doing console.log(index); in the first if statement, which prints the numbers.
(undefined problem):
you're trying to access titles[i]. the problem is that neither items nor i are defined here. What do you see in your console?
You're also trying to pass items to the Insert function as the second argument, but the function declaration doesn't include a second argument.
if you want to print the item's name, you could either pass more information to your function like this:
function Insert(autoParams, currentItemsName) {
db.put(autoParams, function(err, data) {
if (err) throw err;
console.log("Successfully added article: " + currentItemsName + " to the database.");
});
and then call it:
Insert(autoParams, titles[i]);
instead of:
Insert(autoParams, titles);
Or you could use the data that is already available to you inside the function and print that, which is the better option in my opinion.
function Insert(autoParams) {
var currentItemsName = autoParams.Item.title
db.put(autoParams, function(err, data) {
if (err) throw err;
console.log("Successfully added article: " + currentItemsName + " to the database.");
});

How do I get the gender from a particular user when updating a different table? Azure mobile services

I have a table called Subscription and another table called Client I need the gender of the Client who owns the subscription every time I make an update. Here's my update script:
function update(item, user, request) {
var subscriptionId = item.id;
var subscriptionActivitiesTable = tables.getTable("SubscriptionActivity");
var userTable = tables.getTable("User");
var activityTable = tables.getTable("Activity");
var userGender = userTable.where({id: item.UserId}).select('Gender').take(1).read();
console.log(userGender);
activityTable.where({PlanId:item.PlanId, Difficulty: item.Difficulty}).read({
success: function(results){
var startDate = item.StartDate;
results.forEach(function(activity)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (activity.Week*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
})
}
});
var planWeeks = 12;//VER DE DONDE SACAMOS ESTE NUMERO
var idealWeight = 0;
if (userGender === "Male")
{
idealWeight = (21.7 * Math.pow(parseInt(item.Height)/100,2));
}
else
{
idealWeight = (23 * Math.pow(parseInt(item.Height)/100,2));
}
var metabolismoBasal = idealWeight * 0.95 * 24;
var ADE = 0.1 * metabolismoBasal;
var activityFactor;
if (item.Difficulty === "Easy")
{
activityFactor = 1.25;
}
else if(item.Difficulty === "Medium")
{
activityFactor = 1.5;
}
else
{
activityFactor = 1.75;
}
var caloricRequirement = ((metabolismoBasal + ADE)*activityFactor);
activityTable.where(function(item, caloricRequirement){
return this.PlanId === item.PlanId && this.Type != "Sport" &&
this.CaloricRequirementMin <= caloricRequirement &&
this.CaloricRequirementMax >= caloricRequirement;}, item, caloricRequirement).read({
success: function(results)
{
var startDate = item.StartDate;
results.forEach(function(activity)
{
for (var i=0;i<planWeeks;i++)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (i*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
}
})
}
})
request.execute();
}
I tried the code above and clientGender is undefined. As you can see I want to use the gender to set the idealWeight.
The read() method expects a function to be passed in on the success parameter - it doesn't return the result of the query like you'd think.
Try something like this instead:
function update(item, user, request) {
var clientTable = tables.getTable("Client");
var clientGender = 'DEFAULT';
clientTable.where({id: item.ClientId}).select('Gender').take(1).read({
success: function(clients) {
if (clients.length == 0) {
console.error('Unable to find client for id ' + item.ClientId);
} else {
var client = client[0];
clientGender = client.Gender;
// since we're inside the success function, we can continue to
// use the clientGender as it will reflect the correct value
// as retrieved from the database
console.log('INSIDE: ' + clientGender);
}
}
});
// this is going to get called while the clientTable query above is
// still running and will most likely show a value of DEFAULT
console.log('OUTSIDE: ' + clientGender);
}
In this sample, the client table query is kicked off, with a callback function provided in the success parameter. When the query is finished, the callback function is called, and the resulting data is displayed to the log. Meanwhile - while the query is still running, that is - the next statement after the where/take/select/read fluent code is run, another console.log statment is executed to show the value of the clientGender field outside the read function. This code will run while the read statement is still waiting on the database. Your output should look something like this in the WAMS log:
* INSIDE: Male
* OUTSIDE: Default
Since the log shows the oldest entries at the bottom, you can see that the OUTSIDE log entry was written sometime before the INSIDE log.
If you're not used to async or functional programming, this might look weird, but as far as I've found, this is now node works. Functions nested in functions nested in functions can get kind of scary, but if you plan ahead, it probably won't be too bad :-)

Synchronization problem in functions of Javascript

I am developing an application,In that application i have many functions that return us server data.. I have 40 function that needs to be executed 1 by 1 for synchronization to take place.SO i have taken a single function and placed my 40 functions in it... Now the problem is that some of these function skip performing database operations
My one out of 40 function to perform this is
function sync_down_client_info(){
try {
parent.parent.parent.stmt_select.text = "select query";
parent.parent.parent.stmt_select.execute();
parent.parent.parent.result = parent.parent.parent.stmt_select.getResult();
if (parent.parent.parent.result.data != null) {
for (var i = 0; i < parent.parent.parent.result.data.length; i++) {
var admin_id = parent.parent.parent.admin_id;
var sync_client_date = parent.parent.parent.result.data[i].last_sync_client;
// alert(admin_id+"======="+ sync_client_date);
GATEWAY = 'http://projects/one_acc/flashservices/gateway.php';
conn = new parent.parent.parent.air.NetConnection();
conn.connect(GATEWAY);
response = new parent.parent.parent.air.Responder(clientresult, clientFault);
conn.call('down_client_info', response,admin_id,sync_client_date);
response = new parent.parent.parent.air.Responder(clientserverdatetimeResult, clientserverdatetimeFault);
conn.call('check_datetime', response);
}
};
and clientresult function is
function clientresult(e)
{
for (var i=0; i<e.length; i++) {
//alert(e.length);
parent.parent.parent.stmt_select.text="select query ;
parent.parent.parent.stmt_select.execute();
parent.parent.parent.result = parent.parent.parent.stmt_select.getResult();
if(parent.parent.parent.result.data!=null){
parent.parent.parent.stmt_insert.text= "update client_info ;
parent.parent.parent.stmt_insert.execute();
}
can anyone tell me how to do this syncing?
jQuery has constructs like the AjaxQueue to avoid these race conditions you are seeing. I'd advise using these plugins.
Refer http://plugins.jquery.com/project/ajaxqueue

Categories

Resources