How to get nested elements in Google App script / JavaScript - javascript

I need to get values {nb_conversions":58"} under idgoal=ecommerceAbandonedCart, idgoal=4 and so on , I have tried different ways but unsuccessful, would appreciate it if someone can quickly sort this out for me.
Here is API URL: https://demo.matomo.cloud/?module=API&method=UserCountry.getRegion&idSite=1&period=day&date=yesterday&format=JSON&token_auth=anonymous
Sample Data:
[{"label":"Unknown","nb_uniq_visitors":558,"nb_visits":590,"nb_actions":980,"nb_users":0,"max_actions":14,"sum_visit_length":76439,"bounce_count":408,"nb_visits_converted":45,"goals":{"idgoal=ecommerceAbandonedCart":{"nb_conversions":58,"nb_visits_converted":58,"revenue":16199.299999999997,"items":88},"idgoal=ecommerceOrder":{"nb_conversions":10,"nb_visits_converted":10,"revenue":606.7,"revenue_subtotal":2448,"revenue_tax":0,"revenue_shipping":0,"revenue_discount":22.45,"items":12},"idgoal=4":{"nb_conversions":2,"nb_visits_converted":2,"revenue":2},"idgoal=5":{"nb_conversions":1,"nb_visits_converted":1,"revenue":5},"idgoal=6":{"nb_conversions":2,"nb_visits_converted":2,"revenue":4},"idgoal=7":{"nb_conversions":16,"nb_visits_converted":16,"revenue":16},"idgoal=8":{"nb_conversions":13,"nb_visits_converted":13,"revenue":0},"idgoal=10":{"nb_conversions":1,"nb_visits_converted":1,"revenue":0}},"nb_conversions":45,"revenue":633.7,"region":"xx","country":"xx","country_name":"Unknown","region_name":"Unknown","logo":"plugins\/Morpheus\/icons\/dist\/flags\/xx.png"}]
function Goals() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Goals");
var lastRow = sheet.getLastRow();
var today = sheet.getRange(1,6).getValue().toDateString();
var startDate = sheet.getRange(lastRow,1).getValue();
var now = sheet.getRange(lastRow,1).getValue().toDateString();
var dt = new Date(startDate);
//Logger.log(now);
// Logger.log(today);
//Logger.log(dt);
if( today != now){
var response = UrlFetchApp.fetch("https://demo.matomo.cloud/?module=API&method=UserCountry.getRegion&idSite=1&period=day&date=yesterday&format=JSON&token_auth=anonymous");
var json=response.getContentText();
var dataSet=JSON.parse(json);
for(var i = 0; i < dataSet.length; i++)
{
sheet.getRange(i+lastRow+1,2).setValue([dataSet[i]['label']]);
sheet.getRange(i+lastRow+1,3).setValue([dataSet[i]['nb_visits']]);
sheet.getRange(i+lastRow+1,4).setValue([dataSet[i]['nb_uniq_visitors']]);
sheet.getRange(i+lastRow+1,5).setValue([dataSet[i]['goals']['idgoal=ecommerceAbandonedCart']]);
sheet.getRange(i+lastRow+1,1).setValue(now);
}
dt.setDate(dt.getDate()+1);
lastRow = sheet.getLastRow();
sheet.getRange(lastRow+1,1).setValue(dt);
}
}

Given your sample data, try fetching the keys using Object.keys() and loop them one by one to get all nb_conversions instead of passing the idgoals individually. See below:
Code:
var dataSet = [{"label":"Unknown","nb_uniq_visitors":558,"nb_visits":590,"nb_actions":980,"nb_users":0,"max_actions":14,"sum_visit_length":76439,"bounce_count":408,"nb_visits_converted":45,"goals":{"idgoal=ecommerceAbandonedCart":{"nb_conversions":58,"nb_visits_converted":58,"revenue":16199.299999999997,"items":88},"idgoal=ecommerceOrder":{"nb_conversions":10,"nb_visits_converted":10,"revenue":606.7,"revenue_subtotal":2448,"revenue_tax":0,"revenue_shipping":0,"revenue_discount":22.45,"items":12},"idgoal=4":{"nb_conversions":2,"nb_visits_converted":2,"revenue":2},"idgoal=5":{"nb_conversions":1,"nb_visits_converted":1,"revenue":5},"idgoal=6":{"nb_conversions":2,"nb_visits_converted":2,"revenue":4},"idgoal=7":{"nb_conversions":16,"nb_visits_converted":16,"revenue":16},"idgoal=8":{"nb_conversions":13,"nb_visits_converted":13,"revenue":0},"idgoal=10":{"nb_conversions":1,"nb_visits_converted":1,"revenue":0}},"nb_conversions":45,"revenue":633.7,"region":"xx","country":"xx","country_name":"Unknown","region_name":"Unknown","logo":"plugins\/Morpheus\/icons\/dist\/flags\/xx.png"}];
for (var i = 0; i < dataSet.length; i++) {
// Upon testing your linked data, some of them doesn't have goals key.
// Be sure to only access those who have goals to avoid encountering an error.
if(dataSet[i]['goals']) {
Object.keys(dataSet[i]['goals']).forEach(function (idgoal){
Logger.log(dataSet[i]['goals'][idgoal]['nb_conversions']);
});
}
}
Output:
Note:
I recommend you format the data or view it in a site like this one. It really helps a lot.
The nb_conversions being fetched above are only the ones under the goals key.
If some idgoals doesnt have nb_conversions, just skip them like in goals above. The linked data above all has nb_conversions so I didn't include them for now.
References
Object.keys()

Related

Google Apps Script - XML Parser - Regex

I am using a Google Apps Script that pulls the content from a feed in a sheet.
This is the code that I'm using:
function processXML(FeedURL,sheetsFileDestinationURL,rawPasteSheetName,OPT_childNamesArray,OPT_Namespace){
var OPT_childNamesArray = ["link"]; // get only item url from the feed
var GoogleSheetsFile = SpreadsheetApp.openByUrl(sheetsFileDestinationURL);
var GoogleSheetsPastePage = GoogleSheetsFile.getSheetByName(rawPasteSheetName);
if (OPT_childNamesArray){
GoogleSheetsPastePage.getDataRange().offset(1,0).clearContent(); // get all filled cells, omitting the header row, and clear content
}
else {
GoogleSheetsPastePage.getDataRange().offset(0,0).clearContent(); // get all filled cells, INCLUDING the header row, and clear content
}
// Generate 2d/md array / rows export based on requested columns and feed
var exportRows = []; // hold all the rows that are generated to be pasted into the sheet
var XMLFeedURL = FeedURL;
var feedContent = UrlFetchApp.fetch(XMLFeedURL).getContentText(); // get the full feed content
var feedItems = XmlService.parse(feedContent).getRootElement().getChild('channel').getChildren('item'); // get all items in the feed
for (var x=0; x<feedItems.length; x++){
// Iterate through items in the XML/RSS feed
var currentFeedItem = feedItems[x];
var singleItemArray = []; // use to hold all the values for this single item/row
// Parse for specific children (requires names and namespace)
if (OPT_childNamesArray){
for (var y=0; y<OPT_childNamesArray.length; y++){
// Iterate through requested children by name and fill rows
var currentChildName = OPT_childNamesArray[y];
if (OPT_Namespace){
if (currentFeedItem.getChild(OPT_childNamesArray[y],OPT_Namespace)){
singleItemArray.push(currentFeedItem.getChildText(OPT_childNamesArray[y],OPT_Namespace));
}
else {
singleItemArray.push("null");
}
}
else {
if (currentFeedItem.getChild(OPT_childNamesArray[y])){
singleItemArray.push(currentFeedItem.getChildText(OPT_childNamesArray[y]));
}
else {
singleItemArray.push("null");
}
}
}
exportRows.push(singleItemArray);
}
// Parse for ALL children, does not require knowing names or namespace
else if (!OPT_childNamesArray){
var allChildren = currentFeedItem.getChildren();
if (x == 0){
// if looking at first item, create a header row first with column headings
var headerRow = [];
for (var h=0; h<allChildren.length; h++){
headerRow.push(allChildren[h].getName());
}
exportRows.push(headerRow);
}
for (var c=0; c<allChildren.length; c++){
singleItemArray.push(allChildren[c].getText());
}
exportRows.push(singleItemArray);
}
}
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
}
else if (!OPT_childNamesArray){
var maxRangeLength = 0;
var currentRowIndex = 1;
for (var x = 0; x<exportRows.length; x++){
if (exportRows[x].length > maxRangeLength){
maxRangeLength = exportRows[x].length;
}
GoogleSheetsPastePage.getRange(currentRowIndex,1,1,exportRows[x].length).setValues([exportRows[x]]);
currentRowIndex++;
}
}
}
My problem is this:
When I run this code I get:
https://url/115-396/
https://url/115-396/
https://url/115-396/
I need to remove "115-396/".
So I tryed to add this code but didn't work:
...
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
for (var k = 0; k < exportRows.length; k++) {
var re = '115-396/'
var replacingItem = '';
var URL = exportRows[0].toString().replace(re, replacingItem);
}
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValue(URL);
}
else if (!OPT_childNamesArray){
...
Edit after #Yuri reply:
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
for ( k=0; k < exportRows[0].length; k++) {
var re = '115-396/'
var replacingItem = '';
exportRows[0][k] = exportRows[0][k].toString().replace(re, replacingItem);
}
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
}
result:
https://url/
https://url/115-396/
https://url/115-396/
Basically, the regex is applied only to the first url.
How I can make that the regex is applied to all the url's?
Any help?
Thanks
You are using a for to iterate thru the exportRow array, but later on, you're not using the k iterator inside the for.
Then, you are not accessing the exportRows array, only the first position:
var URL = exportRows[0].toString().replace(re, replacingItem);
Shouldn't be?
var URL = exportRows[k].toString().replace(re, replacingItem);
In that case, it won't work, because URL it's not an array, so by doing this you are only saving the last assignation produced on the for iterator on the URL, I believe you are trying to do the following:
for ( k=0; k < exportRows.length; k++) {
var re = '115-396/'
var replacingItem = '';
exportRows[k] = exportRows[k].toString().replace(re, replacingItem);
}
And you'll have exportRows as an array of the desired url's without the 115-396 extensions.
Now you can place this on the spreadsheet with setValue as you were doing, but setValue is for strings, integers, etc, and not for arrays. For arrays you have setValues()
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
But, then, the range of exportRows should match the range of your getRange selection, which I'm not sure it's happening.
Just to clarify it, exportRows.length is the length of the array, and exportRows[1] is the length of the string/url stored on the position 1 of the array.
Hope this helps, the question is not really clear neither the intentions, provide more info if still not working.
How to know the size of the range you're getting?
var myrange = GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length)
Logger.log(myrange.getNumRows());
Logger.log(myrange.getNumColumns());
You'll be able to know the range you have on getRange and make it match with the exportRows size.
Make sure to check the attached documentation, and in case you have more doubts please open a new question related to it.

How to access cell data from iframe Google Sheets

I'm trying to pull two specific numbers from a chart on a football website (Column PF, Row "Team Stats" and "Opp. Stats") and import them to my website as a JavaScript variable which I can do math, etc. with. My solution thus far since I don't want to get into anything too crazy has been use the IMPORTHTML function in Google Sheets, create a table, then export that bit of the spreadsheet using the "publish to web" feature which condenses it into an iframe.
I've tried using object properties of the iframe to access it including a getElementbyId dot property among others.
<h1>
<script>
var iframe = document.getElementById("data");
var elmnt = iframe.contentWindow.document;
//.getElementsByTagName("table")[0];
document.write(elmnt);
window.parent.document.getElementById('data')
</script>
</h1>
I was hoping for an output of the correct number but am getting [object HTMLDocument] or undefined depending on the properties I'm trying
Why don't you use the Sheets API ?
Using the api, you would use this simple command :
var result = Sheets.Spreadsheets.Values.get(spreadsheetId, range);
var numRows = result.values ? result.values.length : 0;
but the setup is a bit heavy
If you dont want to you can still serialize table data.
Here is the work of John Dyer :
function tableToJson(table) {
var data = []; // first row needs to be headers var headers = [];
for (var i=0; i<table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,'');
}
// go through cells
for (var i=1; i<table.rows.length; i++) {
var tableRow = table.rows[i]; var rowData = {};
for (var j=0; j<tableRow.cells.length; j++) {
rowData[ headers[j] ] = tableRow.cells[j].innerHTML;
} data.push(rowData);
}
return data;
}
the you'll can use data[column][row] to get the cell data;
In my opinion using the API is the best option in this specific case.

Need help populating Google Sheets from nested JSON

thanks in advance for any help.
I'm trying to get data from my Hubspot account into a Google Sheet, using their Analytics API (https://developers.hubspot.com/docs/methods/analytics/get-analytics-data-breakdowns)
I've written the following script in Google App Script:
var url = API_URL + "/analytics/v2/reports/totals/summarize/daily?&start=20181201&end=20181219";
var response = UrlFetchApp.fetch(url, headers);
var json = response.getContentText();
var dataALL = JSON.parse(json);
var dataSet = dataALL;
Logger.log(dataALL);
var rows = [],
data;
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push(data.visits, data.leads);
}
Logger.log(rows)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getActiveSheet();
dataRange = sheet.getRange(1, 1, rows.length, 2);
dataRange.setValues([rows])
But when I try Logger.log(rows) it comes out empty. When I try Logger.log(dataSet.length) it returns 0.0
So I gather I'm making a mistake getting the JSON data into the array. I've done tones of research, but could not find a solution that works for my specific case.
The JSON I'm trying to write into the spreadsheet has the following format:
{2018-12-03 = [
{
contactsPerPageview=0.15384615384615385,
rawViews=143,
subscribers=1,
contactToCustomerRate=0.045454545454545456,
privacyConsentDeclines=11,
customersPerPageview=0.006993006993006993,
sessionToContactRate=0.2037037037037037,
pageviewsPerSession=1.3240740740740742,
opportunities=3,
visits=108,
visitors=98,
submissionsPerPageview=0.027972027972027972,
submissions=4,
leads=17,
privacyConsentApproves=9,
customers=1,
contacts=22,
newVisitorSessionRate=0.9074074074074074
}
],
2018-12-14 = [
{
contactsPerPageview=0.06722689075630252,
rawViews=238,
subscribers=4,
privacyConsentDeclines=14,
sessionToContactRate=0.08290155440414508,
pageviewsPerSession=1.233160621761658,
opportunities=6,
visits=193,
visitors=182,
submissionsPerPageview=0.029411764705882353,
submissions=7,
leads=6,
privacyConsentApproves=12,
contacts=16,
newVisitorSessionRate=0.9430051813471503
}]}
Can you guys point me in the right direction?
Thanks again,
Since dataSet is an object, it does not have a .length property, and your for loop will check if i is smaller than Undefined, which results in false. This means the for loop never runs.
I think what you're trying to achieve is closer to the following:
var dataSet = Object.keys(dataALL);
Logger.log(dataALL);
var rows = [], data;
for (i = 0; i < dataSet.length; i++) {
data = dataALL[dataSet[i]];
rows.push(data[0].visits, data[0].leads);
}
Logger.log(rows)
Note that since each key in your object contains an array, I also added [0] to both data.visits and data.leads, resulting in rows.push(data[0].visits, data[0].leads);.

Service error: Spreadsheets using isblank()

I have a big problem since 2 days, my functiun doesn't work anymore :/
"Service error: Spreadsheets" at "if (cell.isBlank())"
function miseEnForme(){
var classeur = SpreadsheetApp.getActive();
var feuilleAdm = classeur.getSheetByName("SuiviAdministratif");
var lastRow;
for (var row = 3; row < 1000; row++) {
var cell=feuilleAdm.getRange(row,3);
if (cell.isBlank()) {
lastRow =row;
break;
}
}
for (var i =3; i<lastRow;i++){
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="RS" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RP" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RD")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("red");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="C")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("#00ff00");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="O")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("white");
}
}
Is it my fault or Google have change something?
How to solve the problem?
Thanks
Checkout this link. I'm guessing that there's nothing wrong with the code. It's just that Google Servers are trying to entice you into using a more batch oriented approach. For example you could get all of your data with one call to var datA=sheet.getDataRange().getValues(); and then you would have all of your data in a 2 dimensional array. It would be easier for Google servers to handle your process and it would perform much better for you. I'll take a copy of your code and see if I can simplify it for you. Perhaps you could give me an idea of what your data looks like.
I haven't tested this code. If you can share some of your data with me I'll be glad to do so. This should be pretty close though. I tried to follow the same basic approach that you were using so you could figure out what's happening a little easier.
function miseEnForme()
{
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sht = ss.getSheetByName("SuiviAdministratif");
var datrng = sht.getDataRange();
var datA = datrng.getValues();//datA is a 2 dimensional array starts at zero
var lastCol = datrng.getLastColumn();
for(var i=2;i<datA.length;i++)
{
if(datA[1][i] == ("RS" || "RP" || "RD"))
{
sht.getRange(i+1,1,1,lastCol).setBackground('#ff0000');
}
if(datA[1][i] == "C")
{
sht.getRange(i+1,1,1,lastCol).setBackground('#00ff00');
}
if(datA[1][i] == "O")
{
sht.getRange(i+1,1,1,lastCol).setBackground('#ffffff');
}
}
}
As Cooper say, your code is not the problem here.
Otherwise, a little workaround will help you :
function miseEnForme(){
var classeur = SpreadsheetApp.getActive();
var feuilleAdm = classeur.getSheetByName("SuiviAdministratif");
// getLastRow() return the value of the last row used in the sheet
var lastRow = feuilleAdm.getLastRow();
for (var i =3; i<lastRow;i++){
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="RS" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RP" || feuilleAdm.getRange("B"+i).getDisplayValue()=="RD")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("red");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="C")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("#00ff00");
if (feuilleAdm.getRange("B"+i).getDisplayValue()=="O")
feuilleAdm.getRange("SuiviAdministratif!A"+i+":AB"+i).setBackground("white");
}
}
More about the getLastRow method : https://developers.google.com/apps-script/reference/spreadsheet/sheet#getLastRow()

How can I output the contents of a scripted array in a google sheets?

I'm a totally new to coding and Google App script, so I humbly ask my question.
I have look all over the place for an answer to this problem and can't seem to find a way to solve it.
Below is my code that gets data from Google Sheets based on their IDs. I can bring the data in and add for 4 sheets and from a particular range.
The script successfully stores the data in an array(arr).
The script sends the data the size of the original import range to the active sheet.
But, how can I output all of the data I can see logged in the array (arr)?
I've tried changing the range size of the output, but to no avail, it just causes and error.
function GetData() {
var classes = ["1XN9NPs_irdpVBEuy0saY-m_PjMW8BxIOgvLkaekdMXo",
"1XN9NPs_irdpVBEuy0saY-m_PjMW8BxIOgvLkaekdMXo",
"11Pdsixi17YjtePg4L780mtGkElWU7TUmshYtJnzxbMU",
"11y8ILVN3lTCWaQYr0nhLdDdLsDDoRqcR2BHz42leUbI"];
var ui = SpreadsheetApp.getUi();
for (var j = 0; j < classes.length; j++) {
var exSs = SpreadsheetApp.openById(classes[j]);
var exSheet = exSs.getSheetByName("tastodolist");
var range = "A4:F10"
var exRange = exSheet.getRange(range);
var values = exRange.getValues();
var arr = [];
arr.push(values);
for (var i = 0; i < arr.length; i++) {
//The log contains all the data that is needed.
Logger.log(arr[i]);
}
//I'm struggling to get all of the logged data into the active
sheet - my code can only output 7 rows of data.
SpreadsheetApp.getActiveSheet().getRange(1,1,7,6).setValues(arr[i]);
}
}
You're only getting 7 rows and 6 columns of the sheet, get all the array's size to output it entirely:
SpreadsheetApp.getActiveSheet().getRange(1,1,arr.length,arr[0].length).setValues(arr[i]);
Also, this is primarily a [google-apps-script] question.

Categories