Need your help and expert guidance as I need my google sheet to send emails every time a condition becomes true in "K" column which is named "Subject" as a header in the tab name "Analysis". Whenever I run the below code. Similarly last 3 lines I get while running the code as errors. Please explain in a simple possible way and not too much technical
function sendEmail(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Analysis");
var range = ss.getRange("J2:J35");
range.clear();
var n = ss.getLastRow();
for (var i = 2;i<n+1; i++){
var emailRequired = ss.getRange(i,9).getValue();
var subject = ss.getRange(i,11).getvalue();
var message = ss.getRange(i,12).getvalue();
if (emailRequired=="YES"){
MailApp.sendEmail("ksm272364#gmail.com",subject,message);
ss.getRange(i,10).setvalue("YES");
}
}
}
1:21:51 PM Error
TypeError: ss.getRange(...).getvalue is not a function
sendEmail # Code.gs:8
I need to import some information from a JSON API URL into Google Sheets.
This is one example:
https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391
I've been successful in importing basic information using IMPORTJSON available on Github:
https://github.com/bradjasper/ImportJSON/
But now I am faced with a type of information (is it an object? an array?) which seems to be different from the usual and I find myself unable to import this.
Here is a piece of it:
{
"id": 969228010,
"raceId": 69357391,
"pegaId": 20042,
"gate": 8,
"pegaAttributes": "{\"id\":20042,\"name\":\"Bajaj\",\"ownerId\":623299,\"raceClass\":1,\"races\":1369,\"win\":504,\"lose\":865,\"energy\":18,\"gender\":\"Male\",\"bloodLine\":\"Campona\",\"breedType\":\"Legendary\",\"speed\":4.95,\"strength\":0.33,\"wind\":3.36,\"water\":1.84,\"fire\":8.83,\"lighting\":6.93,\"position\":4000,\"finished\":true,\"raceTime\":35.855,\"result\":8,\"gate\":8,\"lastSpeed\":22.721521955555556,\"stage\":4,\"isTopSpeedReached\":false,\"bonusStage\":false,\"topSpeed\":22.721521955555556,\"s0\":0,\"j0\":-0.02,\"a0\":0.4982185622222222,\"v0\":20.127527583333332,\"t0\":179.60000000000002,\"gears\":{},\"pb\":0}"**,
"position": 11,
"raceTime": 35.855,
"reward": 0
},
So using IMPORTJSON if I wanted to simply import the "raceId" element I'd go about doing this:
=ImportJSON("https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391", "/race/registers/raceId", "noHeaders")
But when trying to import any information from within pegaAttributesthe IMPORTJSON is unable to recognize it as separate. The best I can do is import the whole block like so:
=ImportJSON("https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391", "/race/registers/pegaAttributes", "noHeaders")
So some of the information after "pegaAttributes" and inside brackets { } I need to import. For example the attributes raceTime , topSpeed, lastSpeed and so on, how can I import this into Google Sheets?
Could anyone provide any pointers on how to do this? Thank you.
Try (you will have to apply JSON.parse on the pegaAttributes element which is also a json)
=importDataJSON(url,"id|position|raceTime","name|raceTime|topSpeed|lastSpeed")
with
function importDataJSON(url, items1, items2) {
let result = []
result = [[items1.split('|'), items2.split('|')].flat()]
const obj = JSON.parse(UrlFetchApp.fetch(url).getContentText())
obj.race.registers.forEach(o => {
let prov = []
items1.split('|').forEach(item1 => prov.push(o[item1]))
var pegaAttributes = JSON.parse(o.pegaAttributes)
items2.split('|').forEach(item2 => prov.push(pegaAttributes[item2]))
result.push(prov)
})
return result
}
with as parameters:
url
items1 (level 1) separated by |
items2 (level2, under pegaAttributes) separated by |
new edit
=importDataJSON(url,"totalReward|length","id|position|raceTime","name|raceTime|topSpeed|lastSpeed")
with
function importDataJSON(url, items0, items1, items2) {
let result = []
result = [[items0.split('|'), items1.split('|'), items2.split('|')].flat()]
const obj = JSON.parse(UrlFetchApp.fetch(url).getContentText())
let prov = []
items0.split('|').forEach(item0 => prov.push(obj.race[item0]))
result.push(prov)
obj.race.registers.forEach(o => {
let prov = []
items0.split('|').forEach(item0 => prov.push(''))
items1.split('|').forEach(item1 => prov.push(o[item1]))
var pegaAttributes = JSON.parse(o.pegaAttributes)
items2.split('|').forEach(item2 => prov.push(pegaAttributes[item2]))
result.push(prov)
})
return result
}
You have to parse it twice as that's an object just as text. I think using the custom formula might not be easiest since Google App Scripts can do this for you pretty cleanly. Consider using the standard JSON.parse() functions.
The below function got me the following values you were looking for. See the debug screen shot.
function getJSONData(){
const zURL = 'https://api-apollo.pegaxy.io/v1/game-api/race/details/69357391';
var response = UrlFetchApp.fetch(zURL);
var cleanedResponse = JSON.parse(response);
var theRace = cleanedResponse['race'];
var theRegisters = theRace['registers'];
var aRegister = theRegisters[0];
var oneID = oneRegister.id;
var aGate = oneRegister.gate;
var aPega = oneRegister.pegaAttributes;
var cleanedPega = JSON.parse(aPega);
var zTopSpeed = cleanedPega.topSpeed;
}
If you debug this, function and check to the right in your variables, you should be able to get everything you need. You'll have to find a way to get it back into sheets, but the values are available.
Updated
A request was made to figure out how this could be run as a Sheets Function. leveraging Mike Steelson's approach and presumption for what is needed as far as races... here's a function that could be used. Just paste the URL in the formula.
function getDataMyJSON(theURL) {
const data = JSON.parse(UrlFetchApp.fetch(theURL).getContentText())
const items = ['raceTime','topSpeed','lastSpeed']
let result=[]
data.race.registers.forEach(x => {
let prov = []
prov.push(x.raceId)
var p = JSON.parse(x.pegaAttributes)
items.forEach(i => prov.push(p[i]))
result.push(prov)
})
return result;
}
So then put the URL in the formula and you'd get this...
I want to be able to pick say C3 from a list of Google spreadsheets in a folder.
I have a bunch of structurally identical sheets, but I'd like to be able to provide a sum of the values in C3 across say a hundred sheets in a directory.
Ultimately, would be great to highlight the largest or smallest value of C3 in a directory.
This could be useful in many places where you want to be able to aggregate, aggregate data.
SUGGESTION
If you have hundreds of Google spreadsheet files in a Google Drive folder, I agree with #player0 that it is best to use a script. With the Apps Script, you can:
Automate the process in iterating through Spreadsheet files in your Drive folder.
Filter only the Google Spreadsheet type (e.g you have a bunch of
different file types inside).
Get the range data & process them the way you want.
See this sample below that was derived from existing resources:
Script:
function readSheetsInAFolder() {
//FOLDER_ID is your drive folder ID
var query = '"FOLDER_ID" in parents and trashed = false and ' +
'mimeType = "application/vnd.google-apps.spreadsheet"';
var range = "C3"; //The range to look for on every Spreadsheet files in the Drive folder
var files, pageToken;
var finalRes = [];
do {
files = Drive.Files.list({
q: query,
maxResults: 100,
pageToken: pageToken
});
files.items.forEach(sheet => {
finalRes.push(viewRangeValue(range, sheet.id));
})
pageToken = files.nextPageToken;
} while (pageToken);
const arrSum = array =>
array.reduce(
(sum, num) => sum + (Array.isArray(num) ? arrSum(num) : num * 1),
0
);
var max = Math.max.apply(null, finalRes.map(function(row){ return Math.max.apply(Math, row) })); //Gets the largest number
var min = Math.min.apply(null, finalRes.map(function(row){ return Math.min.apply(Math, row); })); //Gets the smallest number
var sum = arrSum(finalRes) // Gets the sum
console.log('RANGE VALUES: %s \nRANGE: %s \nTOTAL SHEET(s) FOUND: %s \n________________\nSUM OF VALUES: %s \nLargest Value: %s \nSmallest Value: %s',finalRes,range, files.items.length,sum,max,min)
}
function viewRangeValue(range, sheetID) {
var sid = sheetID;
var rn = range;
var parms = { valueRenderOption: 'UNFORMATTED_VALUE', dateTimeRenderOption: 'SERIAL_NUMBER' };
var res = Sheets.Spreadsheets.Values.get(sid, rn, parms);
return res.values.map(num => {return parseInt(num)});
}
Demonstration:
Sample Test Drive Folder (w/ 3 test Spreadsheet files):
Every C3 cell on each of these 3 files contain either 0,10 or 6 value.
On the Apps Script Editor, I've added the Drive & Sheets API on the services:
Result
After running the script:
Resources:
Advanced Drive Service
Drive API Files: list
Sheets API spreadsheets.values.get
Max Value of an array
I'm developing a google spreadsheet that is automatically requesting information from a site, below is the code. The variable 'tokens' is an array consisting of about 60 different 3 letter unique identifiers. The problem that i have been getting is that the code keeps failing to request all information on the site. Instead it falls back (at random) on the validation part, and fills the array up with "Error!" strings. Sometimes its row 5, then 10-12, then 3, then multiple rows, etc. When i run it in debug mode everythings fine, can't seem to be able to reproduce the problem.
Already tried to place a sleep (100ms) but that fixed nothing. Also looked at the amount of traffic the API accepts (10 requests per second, 1.200 per minute, 100.000 per day) , it shouldn't be a problem.
Runtime is limited so i need it to be as efficient as possible. I'm thinking it is an issue of computational power after i pushed all values in the json request into the 'tokens' array. Is there a way to let the script wait as long as necessary for the changes to be committed?
function newGetOrders() {
var starttime = new Date().getTime().toString();
var refreshTime = new Date();
var tokens = retrieveTopBin();
var sheet = SpreadsheetApp.openById('aaafFzbXXRzSi-eXBu9Xh81Ne2r09vM8rLFkA4fY').getSheetByName("Sheet37");
sheet.getRange('A2:OL101').clear();
for (var i=0; i<tokens.length; i++) {
var request = UrlFetchApp.fetch("https://api.binance.com/api/v1/depth?symbol=" + tokens[i][0] + "BTC", {muteHttpExceptions:true});
var json = JSON.parse(request.getContentText());
tokens[i].push(refreshTime);
Utilities.sleep(100);
for (var k in json.bids) {
tokens[i].push(json.bids[k][0]);
tokens[i].push(json.bids[k][1]);
}
for (var k in json.asks) {
tokens[i].push(json.asks[k][0]);
tokens[i].push(json.asks[k][1]);
}
if (tokens[i].length < 402) {
for (var x=tokens[i].length; x<402; x++) {
tokens[i].push("ERROR!");
}
}
}
sheet.getRange(2, 1, tokens.length, 402).setValues(tokens);
}
After making a copy of my perfectly working google sheet, together with the script that comes with it; the script itself does not work anymore in the copy.
I go through the steps of authorizing it as an app but it seems to hang when i run it on the copy. It times out after 540 odd seconds. It seems to be having trouble with DriveApp.createFolder (exectution time 540 seconds). Yet i have not changed anything in the script, works fine on the original one.
Here is the script, im pretty sure everything is fine here, it just doesn't want to work as soon as you make a copy of it. I need to make copies of this sheet for each person in my team but i can't at the moment.
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var date = SpreadsheetApp.getActiveSheet().getRange(3,2).getValue();
var time = SpreadsheetApp.getActiveSheet().getRange(4,2).getValue();
var site = SpreadsheetApp.getActiveSheet().getRange(2,2).getValue();
// iterate through all sheets in the spreadsheet and rename them according to cell B2
for( var j = 0 ; j < sheets.length; j++) {
var sourceSheet = sheets[j];
// get contents of cell B2
var newSheetName = sourceSheet.getRange("B2").getValue();
// rename sheet
sourceSheet.setName(newSheetName);
}
// create a folder from the named SNOWSURVEYS with date
var folder = DriveApp.createFolder('SNOWSURVEYS' + '_' + date + '_'+ site);
// append ".csv" extension to the sheet name
fileName = SpreadsheetApp.getActiveSheet().getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
var folderID = folder.getId();
var folderName = folder.getName();
var ui = UiApp.createApplication().setTitle('Your files have are in your google drive in a folder called ' + folder);
var p = ui.createVerticalPanel();
ui.add(p);
p.add(ui.createAnchor('Click here to go straight to your files ',folder.getUrl()));
SpreadsheetApp.getActive().show(ui)
}
Execution transcript printscreen