i have an app the automatically insert data to mongodb after calling an api in jive, my problem is the response is paginated.
var getAPICall=function(apiLink){
console.log(apiLink);
var response = HTTP.get(apiLink, {
headers: {
Authorization: getAPIToken()
}
});
return response;
}
var getAPIToken = function(){
var token = HTTP.post("https://api.jivesoftware.com/analytics/v1/auth/login?clientId=fakeclientid.i&clientSecret=fakesecret.s");
//console.log(token);
return token.content;
}
the response looks like this.
{"paging":{"next":"https://cloudalytics-api-phx.prod.jivehosted.com:443/analytics/v2/export/activity/lastday?startIndex=100&count=100&show-all=true","itemsPerPage":100,"totalCount":164406,"currentPage":1,"totalPages":1645}, list: [{....}]}
which has next, currentPage and totalPage field
im planning to do a loop for the next page function and stop when totalPage is equal to currentPage
im doing this
var res = getAPICall(baseline);
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
var totalPage = res.data.paging.totalPage;
for(var current = res.data.paging.currentPage ; current <= totalPage ;) {
var res = getAPICall(res.data.paging.next );
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
}
but this statement only runs until the next page with infinite loop. any ways i can do this better with functional approach?
im new in javascript please hammer me.
thanks!
this should be pretty simple with recursion.
var myFunction = function(baseline){
var res = getAPICall(baseline);
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
if (res.data.paging.currentPage != res.data.paging.totalPage) {
myFunction(res.data.paging.next)
}
}
myFunction(baseline);
Related
This problem is very annoying. So, I am making a scheduled trigger run every 24 hours. It simply gets items from one collection does some data processing then appends information to another collection. The functioning code works even when the function runs. But it will not let me save because there are "runtime" errors? Even though it was executed perfectly and returned.
Console Error
> result (JavaScript):
EJSON.parse('{"$undefined":true}')
I suppose this has something to do with returning. but when I return null I get this:
> result:
null
> result (JavaScript):
EJSON.parse('null')
when trying to save I get this at the top of the page:
runtime error during function validation
Function Code:
exports = async function() {
const usersCol = context.services.get("SchoologyDashCluster").db("SchoologyDashApp").collection("users");
const gradesCol = context.services.get("SchoologyDashCluster").db("SchoologyDashApp").collection("grades");
var usersCusor = await usersCol.find( ).toArray();
var gradesCusor = await gradesCol.find( ).toArray();
let insert = [];
for (let i = 0; i < usersCusor.length; i++) {
var user = usersCusor[i];
var userSavedGrades = gradesCusor[i].grades
var currentGrades = await getGrades(user.schoologyUID, user.consumerKey, user.secretKey);
var lastGraded = NaN;
let index = gradesCusor[i].grades.length - 1;
while (true) {
if (gradesCusor[i].grades[index].changed == 1) {
lastGraded = index;
break
}
index = index - 1;
}
console.log(lastGraded)
if (userSavedGrades[lastGraded].grades.ga == currentGrades.ga){
currentGrades = { changed : 0, time: new Date().getTime()};
} else {
currentGrades = {changed : 1, grades: currentGrades, time : new Date().getTime()};
}
gradesCol.updateOne(
{"user" : user._id},
{"$push" : {"grades" : currentGrades}}
)
}
// return usersCol.find( );
return null;
};
The answer was simple and now I feel ignorant. Instinctual I put the module imports at the top of the document. However this is incorrect and they need to be placed in the exports function, like so:
exports = function (x,y,z) {
const http = context.http;
return;
}
This is my piece of code:
.factory('Latest', function(EBSheadless) {
return {
posts: function() {
// Call the API, and define the specific endpoint
return EBSheadlessDrupalAPI.loadEndpoint('views/news.json');
},
post: function(posts,id,callback){
var findpost = {};
for(var i=0;i<posts.length;i++) {
findpost[posts[i].nid] = posts[i];
}
callback(findpost[id]);
}
};
})
Its getting right result, e.g:
this-is-a-news
But I need this links like this (I cannot edit backend):
/this-is-a-news
So I have to add / in my callback. I tried many positions but its not working.
How can I solve it? Thanks!
why don't you just concatenate string like this callback("/"+findpost[id]);.This will return /this-is-a-news.
post: function(posts,id,callback){
var findpost = {};
for(var i=0;i<posts.length;i++) {
findpost[posts[i].nid] = posts[i];
}
callback("/"+findpost[id]);
}
I have an CSV parsing function in JavaScript which gets data (movie names) from CSV and gets data using Ajax call in loop.
movies = new Array();
for (var i = 1; i < allData.length; i++) {
var mName = allData[i][0];
var mPath = allData[i][1];
// console.log(decodeURIComponent(mName));
$.get(apiCall, function showData(data) {
if (data) {
mData = data.results;
if (mData.length > 1) {
var urlData = new URLSearchParams(this.url);
var movie_name = urlData.get('query');
movies.push(movie_name);
}
}
})
}
If data got more then one record for any movie it will save it as a conflict in array.
Problem is, I can access movies array inside inner if (but it is in iteration so I can't use that) and at loop end it is not accessible. How can I access that?
You should not make api calls inside a for loop. Instead do this,
movies = new Array();
function makeApiCallForEntireArray(index, arr, cb){
if(arr.length == index){
cb(true);
return;
}
$.get(apiCall, function showData(data) {
if (data) {
mData = data.results;
if (mData.length > 1) {
var urlData = new URLSearchParams(this.url);
var movie_name = urlData.get('query');
movies.push(movie_name);
}
}
makeApiCallForEntireArray(index+1, arr, cb);
})
}
makeApiCallForEntireArray(0, allData, function(){
//api calls finished
//movie accesssible here with all the data
});
You will not be able to access the content added in movies array at the end of the loop because ajax requests are still in progress. You need to do this some other way so that you can be sure that its end of asynch ajax calls.
Im going to use the answer of #Jaromanda X in my question here Can't get the summation in for loop
Promise.all(allData.map(function(d) {
return $.get(apiCall, function showData(data){
return data.results;
});
})).then(function(res) {
//push your movies here...the result of your apiCall is inside the res variable
});
I am writing some JavaScript codes using Parse.com.
To be honest, I have been reading how to use Promise and done lots of research but cannot still figure out how to use it properly..
Here is a scenario:
I have two tables (objects) called Client and InvoiceHeader
Client can have multiple InvoiceHeaders.
InvoiceHeader has a column called "Amount" and I want a total amount of each client's InvoiceHeaders.
For example, if Client A has two InvoiceHeaders with amount 30 and 20 and Client B has got nothing, the result I want to see in tempArray is '50, 0'.
However, with the following codes, it looks like it's random. I mean sometimes the tempArray got '50, 50' or "50, 0". I suspect it is due to the wrong usage of Promise.
Please help me. I have been looking into the codes and stuck for a few days.
$(document).ready(function() {
var client = Parse.Object.extend("Client");
var query = new Parse.Query(client);
var tempArray = [];
query.find().then(function(objects) {
return objects;
}).then(function (objects) {
var promises = [];
var totalForHeader = 0;
objects.forEach(function(object) {
totalForHeader = 0;
var invoiceHeader = Parse.Object.extend('InvoiceHeader');
var queryForInvoiceHeader = new Parse.Query(invoiceHeader);
queryForInvoiceHeader.equalTo('headerClient', object);
var prom = queryForInvoiceHeader.find().then(function(headers) {
headers.forEach(function(header) {
totalForHeader += totalForHeader +
parseFloat(header.get('headerOutstandingAmount'));
});
tempArray.push(totalForHeader);
});
promises.push(prom);
});
return Parse.Promise.when.apply(Parse.Promise, promises);
}).then(function () {
// after all of above jobs are done, do something here...
});
} );
Assuming Parse.com's Promise class follows the A+ spec, and I understood which bits you wanted to end up where, this ought to work:
$(document).ready(function() {
var clientClass = Parse.Object.extend("Client");
var clientQuery = new Parse.Query(clientClass);
clientQuery.find().then(function(clients) {
var totalPromises = [];
clients.forEach(function(client) {
var invoiceHeaderClass = Parse.Object.extend('InvoiceHeader');
var invoiceHeaderQuery = new Parse.Query(invoiceHeaderClass);
invoiceHeaderQuery.equalTo('headerClient', client);
var totalPromise = invoiceHeaderQuery.find().then(function(invoiceHeaders) {
var totalForHeader = 0;
invoiceHeaders.forEach(function(invoiceHeader) {
totalForHeader += parseFloat(invoiceHeader.get('headerOutstandingAmount'));
});
return totalForHeader;
});
totalPromises.push(totalPromise);
});
return Parse.Promise.when(totalPromises);
}).then(function(totals) {
// here you can use the `totals` array.
});
});
I have scoured the other question/answer for this and implemented everything and I still cannot access the values of the object. Here's the code I am using:
function apply_voucher(voucher) {
var dates = $.parseJSON($("[name='dates']").val());
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
if(voucher.length > 0)
{
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_yes_no.push('yes');
voucher_reduction.push(result.voucher_reduction);
} else {
voucher_yes_no.push('no');
}
}, 'json');
});
// check if there are any yes's in the array
if('yes' in voucher_yes_no) {
console.log("no yes's");
} else {
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}
}
}
Apologies for the constant console logging - I'm just trying to track everything to make sure it's all doing what it should. The console output I get from this is below:
...which shows the object containing one value, "1.01" and my console.log of the typeof it to make sure it is actually an object (as I thought I was going mad at one point). After this there is nothing from inside the for-in loop. I have tried jquery's $.each() also to no avail. I can't understand why nothing I'm trying is working!
It does not work because the Ajax call is asynchronous!
You are reading the values BEFORE it is populated!
Move the code in and watch it magically start working since it will run after you actually populate the Array!
function apply_voucher(voucher) {
var room_id = "169";
var dates = $.parseJSON($("[name='dates']").val());
var voucher_reduction = new Array();
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
}
console.log(voucher_reduction);
console.log(typeof voucher_reduction);
for (var prop in voucher_reduction) {
console.log(prop);
console.log(voucher_reduction[prop]);
if (voucher_reduction.hasOwnProperty(prop)) {
console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
}
}
}, 'json');
}
From what it looks like, you plan on making that Ajax call in a loop. For this you need to wait for all of the requests to be done. You need to use when() and then(). It is answered in another question: https://stackoverflow.com/a/9865124/14104
Just to say for future viewers that changing the way I did this to use proper deferred objects and promises, which blew my head up for a while, but I got there! Thanks for all the help, particularly #epascarello for pointing me in the right direction :) As soon as I started doing it this way the arrays began behaving like arrays again as well, hooray!
Here's the final code:
function apply_voucher(voucher) {
var booking_id = $("[name='booking_id']").val();
var dates = $.parseJSON($("[name='dates']").val());
if(voucher.length > 0) {
var data = []; // the ids coming back from serviceA
var deferredA = blah(data, voucher, dates); // has to add the ids to data
deferredA.done(function() { // if blah successful...
var voucher_yes_no = data[0];
var voucher_reduction = data[1];
if(voucher_yes_no.indexOf("yes") !== -1)
{
console.log("at least one yes!");
// change value of voucher_reduction field
var reduction_total = 0;
for(var i = 0; i < voucher_reduction.length; i++) {
reduction_total += voucher_reduction[i];
}
console.log(reduction_total);
}
else
{
console.log("there are no yes's");
}
});
}
}
function blah(data, voucher, dates) {
var dfd = $.Deferred();
var voucher_yes_no = new Array();
var voucher_reduction = new Array();
var cycles = 0;
var dates_length = 0;
for(var prop in dates) {
++dates_length;
}
$.each(dates, function(room_id, these_dates) {
$.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
if(result.result == 'ok') {
voucher_reduction.push(result.voucher_reduction);
voucher_yes_no.push('yes');
} else {
voucher_yes_no.push('no');
}
++cycles;
if(cycles == dates_length) {
data.push(voucher_yes_no);
data.push(voucher_reduction);
dfd.resolve();
}
}, 'json');
});
return dfd.promise();
}
Can you show how voucher_reduction is defined?
I am wondering where the second line of the debug output comes from, the one starting with '0'.
in this line:
console.log(vouncher_reduction[prop]);
^
The name of the variable is wrong (then) and probably that is breaking your code.
I think there are no problem with your loop.
But perhaps with your object.
Are you sure what properties has enumerable ?
Try to execute this to check :
Object.getOwnPropertyDescriptor(voucher_reduction,'0');
If it return undefined, the property was not exist.