Google scipts - cannot convert array to object[][] - json

I am trying to pull some information off poloniex.com and paste into a range in a google sheet and am running into issues when trying to set the values. I am pretty new at this and cannot tell if the issue is with my understanding of how setValues works or if it has to do with the way I'm pushing data into my prices array.
function processPoloAPI() {
var sheet = SpreadsheetApp.openById('<insert sheet id here>')
var APIPullSheet = sheet.getSheetByName("APIPull");
APIPullSheet.getRange('A2:D19999').clearContent();
var url = "https://poloniex.com/public?command=returnChartData&currencyPair=USDT_BTC&start=1405699200&end=9999999999&period=86400"
var responseAPI = UrlFetchApp.fetch(url)
var parcedData = JSON.parse(responseAPI.getContentText());
var prices = new Array ();
prices.push(['Date', 'High', 'Low', 'Open','Close', 'Volume', 'QuoteVolume', 'WeightedAverage'])
for(var key in parcedData)
{
prices.push(parcedData[key]);
}
var length = prices.length
askRange = APIPullSheet.getRange(1, 1, length, 8);
askRange.setValues(prices);
}

How about the following modification?
Modification points :
Data for setValues() is 2 dimensional array.
When it retrieves values using keys from JSON, the upper/lower cases for keys should be matched to JSON data.
In your script, prices is [[Date, High, Low, Open, Close, Volume, QuoteVolume, WeightedAverage], {date=1424304000, volume=46.27631267, high=244, low=225, weightedAverage=239.62777823, quoteVolume=0.19311748, close=244, open=225},,,. If you want to create data that each row only numbers for the keys at the top row, each number has to be retrieved from JSON data.
The modified script which was reflected in these modification points is as follows.
Modified script :
function processPoloAPI() {
var sheet = SpreadsheetApp.openById('<insert sheet id here>')
var APIPullSheet = sheet.getSheetByName("APIPull");
APIPullSheet.getRange('A2:D19999').clearContent();
var url = "https://poloniex.com/public?command=returnChartData&currencyPair=USDT_BTC&start=1405699200&end=9999999999&period=86400"
var responseAPI = UrlFetchApp.fetch(url)
var parcedData = JSON.parse(responseAPI.getContentText());
var prices = new Array ();
prices.push(['Date', 'High', 'Low', 'Open','Close', 'Volume', 'QuoteVolume', 'WeightedAverage'])
var keys = ['date', 'high', 'low', 'open', 'close', 'volume', 'quoteVolume', 'weightedAverage'];
for (var i in parcedData) {
var temp = [];
for (var j in keys) {
temp.push(parcedData[i][keys[j]]);
}
prices.push(temp);
}
var length = prices.length
askRange = APIPullSheet.getRange(1, 1, length, 8);
askRange.setValues(prices);
}
Result :
If I misunderstand your question, I'm sorry.

Related

Is there a way to list the array values in one cell by adding one onto another

I'm making a google sheets app function that checks if the ID in one sheet can be associated with any of the patients (each patient receives an ID), then add it into their file (a single cell next to their name).
I'm at a point where I can get the info into the cell with .copyValuesToRange, but the problem is that all the values are copied into the cell one after another. The desired effect is that I get all values separated by ", ".
Here's my code:
function newCaseIn() {
let app = SpreadsheetApp;
let dest = app.getActiveSpreadsheet().getSheetByName("Baza Danych");
let form = app.getActiveSpreadsheet().getSheetByName("Zgloszenia");
for (let i = 2; i < 200; i++) {
if (form.getRange(i, 2).getValue()) {
while (true) {
form.getRange(i, 3).copyValuesToRange(0, 9, 9, 2, 2);
}
}
}
}
And here's how the database looks: Database FormSubmissions
NOTE: There is a form that comes down to the second sheet to allow people submit new patient files to a specified ID
It could be something like this:
function main() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let dest = ss.getSheetByName("Baza Danych");
let form = ss.getSheetByName("Zgloszenia");
// get all data from the form
var source_data = form.getDataRange().getValues();
source_data.shift(); // remove the header
// make the data object
// in: 2d array [[date,id1,doc], [date,id2,doc], ...]
// out: object {id1: [doc, doc, doc], id2: [doc, doc], ...}
var source_obj = {};
while(source_data.length) {
let [date, id, doc] = source_data.shift();
try { source_obj[id].push(doc) } catch(e) { source_obj[id] = [doc] }
}
// get all data from the dest sheet
var dest_data = dest.getDataRange().getValues();
// make a new table from the dest data and the object
var table = [];
while (dest_data.length) {
let row = dest_data.shift();
let id = row[0];
let docs = source_obj[id]; // get docs from the object
if (docs) row[8] = docs.join(', ');
table.push(row);
}
// clear the dest sheet and put the new table
dest.clearContents();
dest.getRange(1,1,table.length,table[0].length).setValues(table);
}
Update
The code from above clears existed docs in the cells of column 9 and fills it with docs from the form sheet (for relevant IDs).
If the dest sheet already has some docs in the column 9 and you want to add new docs you have to change the last loop this way:
// make a new table from the dest data and the object
var table = [];
while (dest_data.length) {
let row = dest_data.shift();
let id = row[0];
let docs = source_obj[id]; // get docs from the object
if (docs) {
let old_docs = row[8];
row[8] = docs.join(', ');
if (old_docs != '') row[8] = old_docs + ', ' + row[8];
}
table.push(row);
}

Google sheet to BigQuery by GAS

I am following the instruction below link with following code ( to make a app script to send data to big query from google sheet ):
function myFunction() {
var projectId = 'tcndata';
var datasetId = 'dec06';
var tableId = 'dec0601';
var fileId = '1Mb7tN3xshHt0gpsxHkt5Ifje4xAeu7N9Vn_YEQAdcoc';
var ss = SpreadsheetApp.openById(fileId);
var source = ss.getSheetByName("send");
var dataToCopy = source.getRange('A2:D5');
var values = dataToCopy.getValues();
var rowsCSV = values.join("\n");
var data = Utilities.newBlob(rowsCSV, 'application/octet-stream');
function convertValuesToRows(data) {
var rows = [];
var headers = ["Contract","Product","Dest","QTY"] ;
for (var i = 1, numColumns = data.length; i < numColumns; i++) {
var row = BigQuery.newTableDataInsertAllRequestRows();
row.json = data[i].reduce(function(obj, value, index) {
obj[headers[index]] = value;
return obj
}, {});
rows.push(row);
};
return rows;
}
function bigqueryInsertData(data, tableId) {
var insertAllRequest = BigQuery.newTableDataInsertAllRequest();
insertAllRequest.rows = convertValuesToRows(data);
var response = BigQuery.Tabledata.insertAll(insertAllRequest, projectId, datasetId, tableId);
if (response.insertErrors) {
Logger.log(response.insertErrors);
}
}
bigqueryInsertData(Utilities.parseCsv(data.getDataAsString()), tableId);
}
'''
The script also no error but the big query no record data.
Any one can help, to figure out what is reason ?
Thank you
You could see these options:
You should validate the headers’s name, as it needs to match the
column names of the table in BigQuery
You should validate converting the rowsCSV to a blob to use
getDataAsString
You should validate the name of the sheet is correct
ss.getSheetByName("send"); you can use ss.getSheets()[0];
You should validate the range has data source.getRange('A2:D5'). You
can use this format getRange(row, column, numRows, numColumns).Yo can see more documentation about getRange.
Another option is for you to load CSV data from Cloud Storage into a new BigQuery table by. You can see this example:
from google.cloud import bigquery
# Construct a BigQuery client object.
client = bigquery.Client()
# TODO(developer): Set table_id to the ID of the table to create.
# table_id = "your-project.your_dataset.your_table_name"
job_config = bigquery.LoadJobConfig(
schema=[
bigquery.SchemaField("name", "STRING"),
bigquery.SchemaField("post_abbr", "STRING"),
],
skip_leading_rows=1,
# The source format defaults to CSV, so the line below is optional.
source_format=bigquery.SourceFormat.CSV,
)
uri = "gs://cloud-samples-data/bigquery/us-states/us-states.csv"
load_job = client.load_table_from_uri(
uri, table_id, job_config=job_config
) # Make an API request.
load_job.result() # Waits for the job to complete.
destination_table = client.get_table(table_id) # Make an API request.
print("Loaded {} rows.".format(destination_table.num_rows))
You can see this documentation.

Not Able to Scrape table in Google Sheets

With the help of this SO questionsI am trying to scrape the following website. I would like the two teams and the time. For example, the first entry would be Chicago | Miami | 12:30 PM, and the last entry would be Colorado | Arizona | 10:10 PM. My code is as follows
function espn_schedule() {
var url = "http://www.espn.com/mlb/schedule/_/date/20180329";
var content = UrlFetchApp.fetch(url).getContentText();
var scraped = Parser.data(content).from('class="schedule has-team-logos align-left"').to('</tbody>').iterate();
var res = [];
var temp = [];
var away_ticker = "";
scraped.forEach(function(e){
var away_team = Parser.data(e).from('href="mlb/team/_/name/').to('"').build();
var time = Parser.data(e).from('a data-dateformat="time1"').to('</a>').build();
if (away_ticker == "") away_ticker = away_team;
if (away_team != away_ticker) {
temp.splice(1, 0, away_ticker);
res.push(temp);
temp = [];
away_ticker = away_team;
temp.push(time);
}
});
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Schedule");
ss.getRange(ss.getLastRow() + 1, 1, res.length, res[0].length).setValues(res);
}
I get the following error:
TypeError: Cannot read property "length" from undefined. (line 42, file "Code")
Here is a modified solution that works
function espn_schedule() {
var url = "http://www.espn.com/mlb/schedule/_/date/20180329";
var content = UrlFetchApp.fetch(url).getContentText();
var e = Parser.data(content).from('class="schedule has-team-logos align-left"').to('</tbody>').build();
var res = [];
//Logger.log(scraped[0])
var temp = [];
var away_ticker = "";
var teams = Parser.data(e).from('<abbr title="').to('">').iterate();
Logger.log(teams)
var time = Parser.data(e).from('data-date="').to('">').iterate()
Logger.log(time)
for( var i = 0; i<teams.length ; i = i+2)
{
res[i/2] = []
res[i/2][0] = teams[i]
res[i/2][1] = teams[i+1]
res[i/2][2] = new Date(time[i/2]).toLocaleTimeString('en-US')
}
Logger.log(res)
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Schedule");
ss.getRange(ss.getLastRow() + 1, 1, res.length, res[0].length).setValues(res);
}
Modification explained:
1) Since you access only the first table you don't need to iterate during parsing and just get the first table. Also, since you get just the first table, you don't need to use forEach to loop through each element.
var e = Parser.data(content)
.from('class="schedule has-team-logos align-left"')
.to('</tbody>')
.build(); //Use build instead of iterate
2) Instead of parsing the HTML link to get the team name, you can use <abbr title=" element to scrape the name. Furthermore, you can iterate over all the team names in the table to get an array of team names.
var teams = Parser.data(e).from('<abbr title="').to('">').iterate();
3) Similar to the above modification, you can get the time by using the data-date tag. This gives you date which can read by Date() class. Again, we iterate over the table to get all the times
var time = Parser.data(e).from('data-date="').to('">').iterate()
4) Finally, we use for loop to rearrange the teams and time in the array called res. This allows for inserting the data into the sheet directly.
for( var i = 0; i<teams.length ; i = i+2) //each loop adds 2 to the counter
{
res[i/2] = []
res[i/2][0] = teams[i] //even team (starts at zero)
res[i/2][1] = teams[i+1] //vs odd teams
res[i/2][2] = new Date(time[i/2]).toLocaleTimeString('en-US')
}
Reference:
Date(),Date.toLocaleTimeString()
Edit:
Reason for error, in the below code
Parser.data(e).from('href="mlb/team/_/name/').to('"').build()
you are looking for string 'href="mlb/team/_/name/', however it should be href="/mlb/team/_/name/'. Note the difference mlb vs /mlb.
Secondly, in the following code
Parser.data(e).from('a data-dateformat="time1"').to('</a>').build();
The string should be a data-dateFormat, when you inspect the website it shown as dateformat. However, when you call it using URLfetch and log the text, it is shown as dateFormat

Poloniex APi to Google Sheet CSV via Json

I've got the following script that pulls keys from the Poloniex JSON output, but doesn't put the actual data that corresponds to the keys into the actual sheet...it only puts the keys as titles at the top of the sheet.
I'm new to API's, and GAS, and coding in general, so I'm sure I'm missing something incredibly obvious, I'd really appreciate it if you could point out what.
Thanks in advance
function Bitcoin_fromPolo_toCSV() {
//Link the script with a spreasdsheet using the identifier found in the spreadsheet url
var ss = SpreadsheetApp.openById('1cubxxxxxxxxxxxxjDqM');
var APIPullSheet = ss.getSheetByName("APIPull");
// Clear Columns A,B,C,D
APIPullSheet.getRange('A2:D19999').clearContent();
var url = "https://poloniex.com/public?command=returnChartData&currencyPair=BTC_ETH&start=1502344800&end=9999999999&period=14400";
//Fetch pulls data from URL
var responseAPI = UrlFetchApp.fetch(url);
//Parse that JSON
var parcedData = JSON.parse(responseAPI.getContentText());
//Break that Parsed data into fields
//Define the 'stats' array, and populate it from the parced data pulled
// for loop iterates over each 'key' in 'parcedData' pushing that data to 'stats'
var stats = [];
stats.push(['date','high', 'low', 'open', 'close', 'volume', 'quoteVolume', 'weightedAverage']);
for(var key in parcedData.stats)
{
stats.push(parcedData.stats[key]);
}
statsRange = APIPullSheet.getRange(1, 1, stats.length, 8);
statsRange.setValues(stats);
}
How about the following modification?
Modification points :
JSON data from URL is as follows.
[
{
"date": 1502352000,
"high": 0.0899,
"low": 0.08754124,
"open": 0.08795499,
"close": 0.08988724,
"volume": 1390.47552953,
"quoteVolume": 15727.49124739,
"weightedAverage": 0.08841051
},
.
.
]
parcedData doesn't have stats as a key.
Flow for creating data :
Outer forEach() retrieves an element from parcedData.
Inner forEach() retrieves each key from stats[0], and retrieves data from the element of parcedData using the key.
Retrieved data is imported to temp which is 1 dimensional array.
The temp is imported to stats which is 2 dimensional array. After this, temp is initialized.
The script reflected this is as follows.
Modified script :
function Bitcoin_fromPolo_toCSV() {
var ss = SpreadsheetApp.openById('1cubxxxxxxxxxxxxjDqM');
var APIPullSheet = ss.getSheetByName("APIPull");
APIPullSheet.getRange('A2:D19999').clearContent();
var url = "https://poloniex.com/public?command=returnChartData&currencyPair=BTC_ETH&start=1502344800&end=9999999999&period=14400";
var responseAPI = UrlFetchApp.fetch(url);
var parcedData = JSON.parse(responseAPI.getContentText());
var stats = [];
stats.push(['date','high', 'low', 'open', 'close', 'volume', 'quoteVolume', 'weightedAverage']);
parcedData.forEach(function(e1){
var temp = [];
stats[0].forEach(function(e2){
temp.push(e1[e2])
});
stats.push(temp);
});
statsRange = APIPullSheet.getRange(1, 1, stats.length, 8);
statsRange.setValues(stats);
}
Result :
If I misunderstand your question, I'm sorry.

How to Iterate to output data to Google Sheets with App-Script

Using Google App Script, when I used Logger.log() the for loop iterates properly and I get results for each value. When I try to output this to a google sheet only the last value for each variable is output over and over again for the number of goals.length.
Any help is very much appreciated!
function listGoals() {
var sheet = SpreadsheetApp.getActiveSheet();
var filterList = Analytics.Management.Goals.list(accountId, webPropertyId, profileId)
var goals = filterList.items;
for (var i = 0, goal; goal = goals[i]; i++) {
var accountId = goal.accountId;
var propertyId = goal.webPropertyId;
var goalNumber = goal.id;
var goalName = goal.name;
Logger.log('accountId: ' + accountId);
Logger.log('profileId: ' + propertyId);
Logger.log('goal number: ' + goalNumber);
Logger.log('goal name: ' + goalName);
//Logger.log prints for each result
sheet.getRange(1,1,goals.length).setValue(goalNumber);
sheet.getRange(1,2,goals.length).setValue(goalName);
//this only prints out the last value of goalNumber and goalName to the sheet
}
}
It doesn't only print the last results, it just keeps overwriting the old result with the new one.
goals.length only helps if you then supply an array of arrays containing the values looking as such:
[[1, "Goal 1"],
[2, "Goal 2"]]
If you want to print out a list of goalNumber and goalName you need to offset the cell to write in every time.
something like
sheet.getRange(1+i,1).setValue(goalNumber);
sheet.getRange(1+i,2).setValue(goalName);
To speed up the process a bit and not do two calls for every goal you can store the id name pairs as arrays within an array and do one final setValues call after the loop finishes executing.
function listGoals() {
var sheet = SpreadsheetApp.getActiveSheet();
var filterList = Analytics.Management.Goals.list(accountId, webPropertyId, profileId)
var goals = filterList.items;
var goalsToWrite = [];
for (var i = 0, goal; goal = goals[i]; i++) {
goalsToWrite.push([goal.id, goal.name]);
}
sheet.getRange(1, 1, goals.length, 2).setValues(goalsToWrite);
}