Google Apps Script API iterate/ loop through ID individually - google-apps-script

i have an endpoint that i need to go through X number of times (dependent on how many IDs), Each call will need to assign its individual LineItem ID and bring back a JSON response.
I have tried the following code, and it seems I can call the API but can't seem to figure out how to translate the response back to my sheet, so in the case below i may have upto 10 LI ids that will need to be called up individually > results brought back> copied to last row of a particular range and then the next API call with the next LI id, etc...
function ListLI360API_Agetest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('MySheet');
var adID = 1558211;
var LIs =sheet.getRange(2, 3, sheet.getLastRow(), 1).getValues().filter(String);
var LIArrayLength = LIs.length;
for (var i = 0; i <= LIArrayLength; i++) {
if(LIs[i]!== undefined){
var url = 'https://displayvideo.googleapis.com/v1/advertisers/'+adID+'/lineItems/'+LIs[i]+'/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions'
//Logger.log(url);
var response = callApi5 (url, 'GET');
//Logger.log(response);
var content = response.getContentText();
//Logger.log(content);
var json = JSON.parse(content);
//Logger.log(json);
var ageData = json["assignedTargetingOptions"];
//Logger.log(ageData);
var rows = [],
data;
for (i = 0; i <= ageData.length; i++) {
data = ageData[i];
rows.push([data.name]);
}
//save results to spreadsheet in the next blank column and then API for next LI ID
Logger.log(rows);
}
}//endfor
}
I seem to be getting stuck on reading the results, i have tried with the following added into the script above but i get an error
"TypeError: Cannot read property "name" from undefined", im guessing there are some nulls/ blanks being returned in the JSON and hence it cant read the length
JSON looks like...
[20-06-24 21:34:57:159 BST] {
"assignedTargetingOptions": [
{
"name": "advertisers/1558211/lineItems/36917016/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503004",
"assignedTargetingOptionId": "503004",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_45_54",
"targetingOptionId": "503004"
}
},
{
"name": "advertisers/1558211/lineItems/36917016/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503005",
"assignedTargetingOptionId": "503005",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_55_64",
"targetingOptionId": "503005"
}
},
{
"name": "advertisers/1558211/lineItems/36917016/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503006",
"assignedTargetingOptionId": "503006",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_65_PLUS",
"targetingOptionId": "503006"
}
}
]
}
[20-06-24 21:34:57:694 BST] {
"assignedTargetingOptions": [
{
"name": "advertisers/1558211/lineItems/36917017/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503004",
"assignedTargetingOptionId": "503004",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_45_54",
"targetingOptionId": "503004"
}
},
{
"name": "advertisers/1558211/lineItems/36917017/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503005",
"assignedTargetingOptionId": "503005",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_55_64",
"targetingOptionId": "503005"
}
},
{
"name": "advertisers/1558211/lineItems/36917017/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions/503006",
"assignedTargetingOptionId": "503006",
"targetingType": "TARGETING_TYPE_AGE_RANGE",
"inheritance": "NOT_INHERITED",
"ageRangeDetails": {
"ageRange": "AGE_RANGE_65_PLUS",
"targetingOptionId": "503006"
}
}
]
}
From this Example there are 2 LI Ids so 2 separate outputs, i need to take parts of these outputs and print them into the spreadsheet
API function looks like...
function callApi5(url, methodType, requestBody) {
var service = getService();
if (service.hasAccess()) {
var headers = {
'Content-Type': 'application/json',
'Accept' :'application/json',
'Authorization': 'Bearer ' + getService().getAccessToken()
};
var options = {
method: methodType,
headers : headers,
muteHttpExceptions: true
};
if (requestBody) {
options.payload = requestBody;
}
return UrlFetchApp.fetch(url, options);
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s',
authorizationUrl);
}
}
function getService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('MyService')
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId("xxxxx.apps.googleusercontent.com")
.setClientSecret("xxxxxx")
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
// this is blogger read only scope for write access is:
.setScope('https://www.googleapis.com/auth/display-video')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', 'xxxx#xxxs.com')
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}

I believe your goal as follows.
You want to retrieve the values from all requests, which used the URLs created by 'https://displayvideo.googleapis.com/v1/advertisers/'+adID+'/lineItems/'+LIs[i]+'/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions', and put them to the Spreadsheet.
For this, how about this answer? From your question, I thought that your script of callApi5() works and json of var json = JSON.parse(content); is the value you showed in your question. So I would like to propose to modify the function of ListLI360API_Agetest.
Modification points:
When the array is used in the for loop, please loop from 0 to array.length - 1. Because the 1st index of array is 0. So, when for (var i = 0; i <= LIArrayLength; i++) is used, an error occurs at the last loop of LIArrayLength. In this case, please modify to for (var i = 0; i < LIArrayLength; i++). Also, this can be said for for (i = 0; i <= ageData.length; i++) {.
In your script, 1 for loop is included in the for loop. And, each loop uses the variable i. In this case, the variables of i of each loop are affected. By this, the loop cannot be correctly worked.
I think that your error of TypeError: Cannot read property "name" from undefined might be due to above 2 points.
LIs of var LIs =sheet.getRange(2, 3, sheet.getLastRow(), 1).getValues().filter(String); is 2 dimensional array. So in this case, I think that LIs[i][0] is suitable instead of LIs[i].
When above points are reflected to your script, it becomes as follows.
Modified script:
Please copy and paste the following script, and set the destination sheet name to the last line of ss.getSheetByName("###").getRange(1, 10, result.length, 1).setValues(result);.
function ListLI360API_Agetest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('MySheet'); // Modified
var adID = 1558211;
var LIs = sheet.getRange(2, 3, sheet.getLastRow(), 1).getValues().filter(String);
var LIArrayLength = LIs.length;
var result = []; // Added
for (var i = 0; i < LIArrayLength; i++) { // Modified
if (LIs[i][0] !== undefined) { // Modified
var url = 'https://displayvideo.googleapis.com/v1/advertisers/'+adID+'/lineItems/'+LIs[i][0]+'/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions' // Modified
var response = callApi5 (url, 'GET');
var content = response.getContentText();
var json = JSON.parse(content);
var ageData = json["assignedTargetingOptions"];
for (var j = 0; j < ageData.length; j++) { // Modified
var data = ageData[j];
result.push([data.name]); // Modified
}
}
}
// Please set the destination sheet name.
ss.getSheetByName("###").getRange(1, 1, result.length, 1).setValues(result); // Added
}
If data.name is not existing, you don't want to put the values, please modify result.push([data.name]); to if (data.name) result.push([data.name]);.
Note:
In this modified script, it supposes that the structure of JSON object retrieved from each URL is the same. If the structure is different for each URL created by LIs[i][0], it is required to modify the script. Please be careful this.
I couldn't understand the result situation that the values are put to the Spreadsheet from your question. So in this modified script, the values are put to the destination sheet. If this is different from your actual situation, please modify the script.
References:
Array
getValues()

I have tested the answer provided by Tanike and modified the last part to be able to print to the spreadsheet. I have added a few more fields from JSON to test this, and finally added:
dataRange = sheet.getRange(lr+1, 17, result.length,result[0].length).setValues(result);
to print onto the spreadhseet.
function ListLI360API_Agetest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('MySheet'); // Modified
var adID = 1558211;
var LIs = sheet.getRange(2, 3, sheet.getLastRow(), 1).getValues().filter(String);
var LIArrayLength = LIs.length;
var result = []; // Added
var lr = sheet.getRange('Q1').getDataRegion().getLastRow(); //Added
for (var i = 0; i < LIArrayLength; i++) { // Modified
if (LIs[i][0] !== undefined) { // Modified
var url = 'https://displayvideo.googleapis.com/v1/advertisers/'+adID+'/lineItems/'+LIs[i][0]+'/targetingTypes/TARGETING_TYPE_AGE_RANGE/assignedTargetingOptions' // Modified
var response = callApi5 (url, 'GET');
var content = response.getContentText();
var json = JSON.parse(content);
var ageData = json["assignedTargetingOptions"];
for (var j = 0; j < ageData.length; j++) { // Modified
var data = ageData[j];
result.push([
data.name,
data.assignedTargetingOptionId,
data.ageRangeDetails.ageRange]); // Modified
}
}
}
// Each Set of results is pushed one after another
dataRange = sheet.getRange(lr+1, 17, result.length,result[0].length).setValues(result);//Modified
}

Related

How to POST / PUT webhook from Google Sheets when new rows are added

Disclaimer : I'm a newbie and doesn't know much. I understand webhooks a little bit, but doesn't know how to code.
Now that is out of the way, what I'm trying to do is, send data from a CRM to google sheets, do some calculations and send it back. I was able to figure out the first step of sending from CRM and doing the calculations.
Here is what I want to do..
I'd like to be able to send the updated data from googlesheet back to the CRM as a webhook when a new row is added to the google sheets.
So I have created a google sheet, I was able to add a trigger to run myFunction on Edit. My current myFunction code is at the end.
**Ideally it should send "id" and "updated_value" fetched from google sheets to the CRM via webhook (PUT method) as it will be updating a contact record.
Can anyone please share the code to add here or guide me how to write one? Thank you in advance**
This is my code so far and I'm currently finding resources to learn to add more lines to it
Update: One problem I'm facing now is that, I'm getting the 1000th row as the last row as "I've used array function in one column. So I'm not actually getting the non-empty last row.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var range = sheet.getRange(lastRow, 1, 1, lastColumn);
var values = range.getValues();
var data = {
"id": values[0][1],
"f2130": values[0][3]
};
var options = {
'method': 'PUT',
'url': 'https://api.ontraport.com/1/Contacts',
'headers': {
'Content-Type': 'application/json',
'Api-Appid': 'xxxxxxxxxxxxxxx6',
'Api-Key': 'xxxxxxxxxxxxxxxH'
},
body: JSON.stringify({
"f2130": f2130,
"id": id
})
};
UrlFetchApp.fetch("https://api.ontraport.com/1/Contacts", options);
}
I finally able to figure it out by myself. Here is the code
Also you can read the steps here
https://damartech.com/how-to-send-and-receive-data-from-ontraport-to-google-sheet-and-back-without-zapier/
function opUpdater() {
// Replace `spreadsheetId` and `sheetName` with the ID and name of your Google Sheets document
const spreadsheetId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const sheetName = "xxxxxx";
// Get the sheet by ID and name
const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
// Get the number of rows in the sheet
const numRows = sheet.getLastRow();
// Initialize a variable to store the index of the last non-empty row
let lastNonEmptyRowIndex = 0;
// Loop through each row in the sheet
for (let i = 1; i <= numRows; i++) {
// Get the values in the current row
const rowValues = sheet.getRange(i, 1, 1, sheet.getLastColumn()).getValues()[0];
// Check if the row is empty
if (rowValues.every(cell => cell === "")) {
// If the row is not empty, store its index as the last non-empty row
lastNonEmptyRowIndex = i-1;
break;
}
}
// If a non-empty row was found, get its values
if (lastNonEmptyRowIndex > 0) {
const lastNonEmptyRowValues = sheet.getRange(lastNonEmptyRowIndex, 1, 1, sheet.getLastColumn()).getValues()[0];
// Define the variables that will be used in the request
// You can find the values from google sheet column number-1
var contact_id = parseInt(lastNonEmptyRowValues[1]);
var new_date = lastNonEmptyRowValues[3];
}
// Define the URL for the request
let url = "https://api.ontraport.com/1/Contacts";
// Define the options for the request
var options = {
"method": "put",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json",
"Api-Appid": "xxxxxxxxxxxxxxxx",
"Api-Key": "xxxxxxxxxxxxxxxx"
},
"payload": JSON.stringify({
"id": contact_id,
"f2130": new_date
}),
"muteHttpExceptions": true
};
try {
const response = UrlFetchApp.fetch(url, options);
const responseBody = response.getContentText();
const data = JSON.parse(responseBody);
Logger.log(data.data.attrs.id);
Logger.log(data.data.attrs.f2130);
} catch (error) {
Logger.log(error.message);
Logger.log(error.response);
}
}

How to Import JSON data to google sheet with for loop

I almost import my JSON data from API.
But I don't know what is exactly the value of setvalue() in my case.
I want to get a google sheet of the product list loop automatically.
The final output that I want to get is the product list continually looping from page 1 to the last page.
When I run my code on Apps script, I got the output like the screenshot below.
But, It repeats only the first product of the product list.
function dearAPI(endpoint,sheetname,dig) {
const dataRows = [];
let pagenumber = 1;
const a = UrlFetchApp.fetch(
'https://inventory.dearsystems.com/externalapi/v2/product?page=1&limit=10',
{
'method':'get',headers:
{
"api-auth-accountid": accountID,
"api-auth-applicationkey": secret,
},
"contentType": 'application/json'
});
var sheet = SpreadsheetApp.getActiveSheet();
var json = JSON.parse(a.getContentText());
var headers = [Object.keys(json.Products[0])];
sheet.getRange(1,1,headers.length,headers[0].length).setValues(headers);
for(var i = 0; i < json.Products.length; i++){
var rows = [Object.values(json.Products[i])];
var final = Object.values(json.Products[i]);
getFinal = [final[i]];
for (var j = 0; j < json.Products.length; j++){
sheet.getRange(2, i+1, json.Products.length, rows[0].length).setValue(getFinal);
}
}
}
Suggestion:
Assuming this manually created sample JSON below has the same JSON structure from your API:
{
Products=[
{
Name=DarknessPumpLarge,
DropShipMode=NoDropShip,
Brand=Darkness,
DefaultLocation=Toronto,
Category=Accessories,
CostingMethod=FIFO,
Type=Stock
},
{
DropShipMode=NoDropShip,
Name=AppleiPhone,
Type=Stock,
DefaultLocation=California,
Category=Gadget,
Brand=Apple,
CostingMethod=FIFO
},
{
CostingMethod=FIFO,
Brand=Samsung,
DropShipMode=NoDropShip,
DefaultLocation=SouthKorea,
Name=SamsungGalaxyS21,
Category=Gadget,
Type=Stock
}
]
}
NOTE: It would also be better if you can share a snippet of your JSON value for better replication.
You can try this implementation, the script starting from the line with var = headers:
function dearAPI() {
var getFinal = []; //Assuming the `getFinal` was initialized as `an array variable
//Sample JSON value manually imputted here for replication
const json = {
"Products":[
{"Name":"Darkness Pump Large", "Category":"Accessories", "Brand":"Darkness", "Type":"Stock", "CostingMethod":"FIFO", "DropShipMode":"No Drop Ship", "DefaultLocation":"Toronto"},
{"Name":"Apple iPhone", "Category":"Gadget", "Brand":"Apple", "Type":"Stock", "CostingMethod":"FIFO", "DropShipMode":"No Drop Ship", "DefaultLocation":"California"},
{"Name":"Samsung Galaxy S21", "Category":"Gadget", "Brand":"Samsung", "Type":"Stock", "CostingMethod":"FIFO", "DropShipMode":"No Drop Ship", "DefaultLocation":"South Korea"}
]
}
var headers = [Object.keys(json.Products[0])];
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1,1,headers.length,headers[0].length).setValues(headers);
for(var i = 0; i < json.Products.length; i++){
var final = Object.values(json.Products[i]);
getFinal.push(final);
}
sheet.getRange(2,1,getFinal.length,getFinal[0].length).setValues(getFinal);
}
Sample Result:

Ignore same-thread emails that have different labels

I am writing the Date and Subject from specific new emails to a new row of a Google Sheet.
I apply a label to the new mail items with a filter.
the script processes those labeled emails
the label is removed
A new label is applied, so that these emails won't be processed next time.
Problem: When there is a myLabel email, the script processes all emails in the same thread (eg same subject and sender) regardless of their label (even Inbox and Trash).
Question: How to only process new emails i.e. ones with the label myLabel - even when the thread of those messages extends outside the myLabel folder?
My current script:
function fetchmaildata() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('mySheetName');
var label = GmailApp.getUserLabelByName('myLabel');
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++)
{
var sub = messages[j].getSubject();
var dat = messages[j].getDate();
ss.appendRow([dat, sub])
}
threads[i].removeLabel(label);
threads[i].addLabel(newlabel);
}
}
I hacked a solution for my purposes by changing my for loop to this:
for (var j = messages.length-1; j > messages.length-2; j--)
This says to process only the latest email in the thread, even when there is more than one email of a thread in the myLabel folder. Oddly, the script still changes the Labels of all the myLabel emails, but only the latest one of a thread gets written to the spreadsheet, so it works for me.
I had to make another change to the code because the above code does not run as a time-triggered scheduled task. I changed the code in this way and it now runs on a time schedule !!
//var ss = SpreadsheetApp.getActiveSpreadsheet();
var ss = SpreadsheetApp.openById("myGoogleSheetID");
A label can be on a thread due to being on a single message in said thread. Your code simply goes label -> all label threads -> all thread messages, rather than accessing only the messages in a thread with a given label. That's not really your fault - it's a limitation of the Gmail Service. There are two approaches that you can use to remedy this behavior:
The (enable-before-use "advanced service") Gmail REST API
The REST API supports detailed querying of messages, including per-message label status, with Gmail.Users.Messages.list and the labelIds optional argument. For example:
// Get all messages (not threads) with this label:
function getMessageIdsWithLabel_(labelClass) {
const labelId = labelClass.getId();
const options = {
labelIds: [ labelId ],
// Only retrieve the id metadata from each message.
fields: "nextPageToken,messages/id"
};
const messages = [];
// Could be multiple pages of results.
do {
var search = Gmail.Users.Messages.list("me", options);
if (search.messages && search.messages.length)
Array.prototype.push.apply(messages, search.messages);
options.pageToken = search.nextPageToken;
} while (options.pageToken);
// Return an array of the messages' ids.
return messages.map(function (m) { return m.id; });
}
Once using the REST API, there are other methods you might utilize, such as batch message label adjustment:
function removeLabelFromMessages_(messageIds, labelClass) {
const labelId = labelClass.getId();
const resource = {
ids: messageIds,
// addLabelIds: [ ... ],
removeLabelIds: [ labelId ]
};
// https://developers.google.com/gmail/api/v1/reference/users/messages/batchModify
Gmail.Users.Messages.batchModify(resource, "me");
}
Result:
function foo() {
const myLabel = /* get the Label somehow */;
const ids = getMessageIdsWithLabel_(myLabel);
ids.forEach(function (messageId) {
var msg = GmailApp.getMessageById(messageId);
/* do stuff with the message */
});
removeLabelFromMessages_(ids, myLabel);
}
Recommended Reading:
Advanced Services
Gmail Service
Messages#list
Message#batchModify
Partial responses aka the 'fields' parameter
Tracked Processing
You could also store each message ID somewhere, and use the stored IDs to check if you've already processed a given message. The message Ids are unique.
This example uses a native JavaScript object for extremely fast lookups (vs. simply storing the ids in an array and needing to use Array#indexOf). To maintain the processed ids between script execution, it uses a sheet on either the active workbook, or a workbook of your choosing:
var MSG_HIST_NAME = "___processedMessages";
function getProcessedMessages(wb) {
// Read from a sheet on the given spreadsheet.
if (!wb) wb = SpreadsheetApp.getActive();
const sheet = wb.getSheetByName(MSG_HIST_NAME)
if (!sheet) {
try { wb.insertSheet(MSG_HIST_NAME).hideSheet(); }
catch (e) { }
// By definition, no processed messages.
return {};
}
const vals = sheet.getSheetValues(1, 1, sheet.getLastRow(), 1);
return vals.reduce(function (acc, row) {
// acc is our "accumulator", and row is an array with a single message id.
acc[ row[0] ] = true;
return acc;
}, {});
}
function setProcessedMessages(msgObject, wb) {
if (!wb) wb = SpreadsheetApp.getActive();
if (!msgObject) return;
var sheet = wb.getSheetByName(MSG_HIST_NAME);
if (!sheet) {
sheet = wb.insertSheet(MSG_HIST_NAME);
if (!sheet)
throw new Error("Unable to make sheet for storing data");
try { sheet.hideSheet(); }
catch (e) { }
}
// Convert the object into a serializable 2D array. Assumes we only care
// about the keys of the object, and not the values.
const data = Object.keys(msgObject).map(function (msgId) { return [msgId]; });
if (data.length) {
sheet.getDataRange().clearContent();
SpreadsheetApp.flush();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}
Usage would be something like:
function foo() {
const myLabel = /* get label somehow */;
const processed = getProcessedMessages();
myLabel.getThreads().forEach(function (thread) {
thread.getMessages().forEach(function (msg) {
var msgId = msg.getId();
if (processed[msgId])
return; // nothing to do for this message.
processed[msgId] = true;
// do stuff with this message
});
// do more stuff with the thread
});
setProcessedMessages(processed);
// do other stuff
}
Recommended Reading:
Is checking an object for a key more efficient than searching an array for a string?
Array#reduce
Array#map
Array#forEach

Write from Google Firebase to Google Sheets using Google Apps script

Trying to retrieve form entries which are stored in google firebase under the node called entries and append to a google sheet using the script editor in google sheets.
I have added the FirebaseApp library to google sheet script editor. Then my code looks like this:
function getAllData() {
var firebaseUrl = "https://myapp.firebaseio.com/";
var secret = "pCOCwKCC582jpqdZe2EqPqnW3IAd3UyO9oB4uaEL2";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl, secret);
var data = base.getData();
Logger.log(data);
}
when I run this nothing happens. Any ideas?
Next I need to add the returned data from firebase to the google sheet. I was using this code to do this via the sheets api, however I'm not sure how this works in the google script editor?
function addEntries() {
gapi.client.sheets.spreadsheets.values.append({
spreadsheetId: '10lyQpQtEA7euCfdU2isrqB_bgPuy-eSbW74h7oDP3ko',
range: "Sheet1!A1:D100",
majorDimension: "ROWS",
"values": [
["testa", "testb", "testc", "testd"]
],
valueInputOption: 'USER_ENTERED'
}).then(function(response) {
}, function(response) {
appendPre('Error: ' + response.result.error.message);
});
}
I'm using the newest Firebase version. This snippet code works for me.
function getFacturasClientesExistentes() {
var firebaseUrl = "https://test.firebaseio.com/FacturasBLP/clienteExistente";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl);
var data = base.getData();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Facturas Clientes Existentes");
var num = 2;
range = sheet.getRange("A"+num+":F"+num+"");
for(var i in data) {
var values = [
[ data[i].fecha, data[i].sucursal, data[i].cantidad, data[i].cliente, data[i].correo, data[i].estatus ]
];
range.setValues(values);
num += 1;
range = sheet.getRange("A"+num+":F"+num+"");
}
}
Some notes:
I have previously write the headers for my data in the spreadsheet
In the line range = sheet.getRange("A"+num+":F"+num+""); from A to F I have my headers
I hope this helps someone, this worked for me.
function writeSheets() {
var ss = SpreadsheetApp.openById("10lyQpQtEA7euCfdU2isrqB_bgPuy-eSbW74h7oDP3ko");
var sheet = ss.getSheets()[0];
var firebaseUrl = "https://myapp.firebaseio.com/";
var secret = "pCOCwKCC582jpqdZe2EqPqnW3IAd3UyO9oB4uaEL2"; // get this from firebase project settings
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl);
var data = base.getData();
var keys = Object.keys(data.entries);
var sheetRow = [];
var entryKeys;
for (index in keys) {
sheetRow = [];
entryKeys = Object.keys(data.entries[keys[index]])
for (i in entryKeys) {
sheetRow.push(data.entries[keys[index]][entryKeys[i]]);
}
//Logger.log(sheetRow);
sheet.appendRow(sheetRow);
}
}
Note: in order for this code to work, you need to install the firebaseapp library in the script editor as per these instructions, https://sites.google.com/site/scriptsexamples/new-connectors-to-google-services/firebase

"The coordinates or dimensions of the range are invalid"

I am working on a Google Apps Script that links with a REST API and puts the data into a Google Sheet.
I have successfully done this once, but upon accessing some different data I get the error message
"The coordinates or dimensions of the range are invalid"
when they work perfectly fine on my other script. All data accessed is JSON so I am bit confused and is from the same source. The code I am using is:
function stats () {
var logIn = {
"Authorization" : "Basic " + Utilities.base64Encode("XXXX" + ':' + "XXXX")
};
var url = "XXXXX";
var params = {
"method":"GET",
"headers":logIn, };
var response = UrlFetchApp.fetch(url, params);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("XXXX");
var dataAll = JSON.parse(response.getContentText()); //
var dataSet = dataAll;
var rows = [],
data;
for (i = 0; i < dataSet.length; i++) {
data = dataSet[i];
rows.push([XXXX]); //your JSON entities here
}
dataRange = sheet.getRange(1, 1, rows.length, 1);
dataRange.setValues(rows);
}
I have combined pieces of code from around the web and this works on my other script. The error appears on this line:
dataRange = sheet.getRange(1, 1, rows.length, 1);
I believe the issue is with the data I am accessing but I do not know how to alter the script for it to work.
The JSON data that works is shown like:
{
id: XXX,
group: XX,
text: "XXXX?",
creation_date: XXXX,
created_by: "XXXXX",
tags: [
"XXXX"
]
}
And the data that is causing the error is shown as:
{
2016-02-29: {
XXX: 0,
XXX: 0
},
I have had to 'XXXX' out a lot of the private information - apologies. Any help would be appreciated.
Javascript's length property is for indexed arrays and does not apply to Objects so dataSet.length returns undefined and the loop never executes.
To get the length of the object you can use Object.keys(dataSet).length as outlined here.