JSON data not parsed correctly from Google Sheets - json

I'm trying to convert Google Sheets Data to JSON format using a script.
This is a test google sheet: https://docs.google.com/spreadsheets/d/1zEts1AaAseO4MlLf5OA--Ylp-bH9aXe-1pacjstv4GI/edit#gid=0
But the JSON Format looks like this:
which is not correct at all!
Script code is given below with correct credentials of the test sheet:
function doGet(e) {
var sheetName = "TestSheet";
var sheetId = "1zEts1AaAseO4MlLf5OA--Ylp-bH9aXe-1pacjstv4GI";
var book = SpreadsheetApp.openById(sheetId);
var sheet = book.getSheetByName(sheetName);
var json = convertSheet2JsonText(sheet);
return ContentService
.createTextOutput(JSON.stringify(json))
.setMimeType(ContentService.MimeType.JSON);
}
function convertSheet2JsonText(sheet) {
var sheetName = "TestSheet";
var sheetId = "1zEts1AaAseO4MlLf5OA--Ylp-bH9aXe-1pacjstv4GI";
var book = SpreadsheetApp.openById(sheetId);
var sheet = book.getSheetByName(sheetName);
var colStartIndex = 1;
var rowNum = 1;
var firstRange = sheet.getRange(2, 2, 2, sheet.getLastColumn());
var firstRowValues = firstRange.getValues();
var titleColumns = firstRowValues[0];
// after the second line(data)
var lastRow = sheet.getLastRow();
var rowValues = [];
for(var rowIndex=2; rowIndex<=lastRow; rowIndex++) {
var colStartIndex = 1;
var rowNum = 1;
var range = sheet.getRange(rowIndex, colStartIndex, rowNum,
sheet.getLastColumn());
var values = range.getValues();
rowValues.push(values[0]);
}
// create json
var jsonArray = [];
for(var i=0; i<rowValues.length; i++) {
var line = rowValues[i];
var json = new Object();
for(var j=0; j<titleColumns.length; j++) {
json[titleColumns[j]] = line[j];
}
jsonArray.push(json);
}
return jsonArray;
}
I am guessing the logic inside the convertSheet2JsonText function is wrong which is causing the problem. Your help will be much appreciated. Thank you.
The correct JSON format of this test sheet should look like this:

You want to retrieve the following object from the shared spreadsheet using your script.
[
{
"firstName": "john",
"lastName": "doe",
"age": 12,
"place": "boston"
},
{
"firstName": "nahid",
"lastName": "patwary",
"age": 21,
"place": "sylhet"
},
{
"firstName": "kishor",
"lastName": "pasha",
"age": 15,
"place": "california"
}
]
If my understanding is correct, how about this modification? I think that the range for retrieving titleColumns might be the reason of your issue. So how about modifying as follows?
From:
var firstRange = sheet.getRange(2, 2, 2, sheet.getLastColumn());
To:
var firstRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
If I misunderstand your question, please tell me. I would like to modify it.

Related

TypeError: Cannot read property '0' of undefined (Google Sheets / App Script)

I would like to know what I need to adjust in the script so that the results appear in the spreadsheet:
TypeError: Cannot read property '0' of undefined (line 7)
function Cartola() {
var url = "https://api.cartolafc.globo.com/mercado/destaques";
var response = UrlFetchApp.fetch(url);
var data = response.getContentText();
var result = JSON.parse(data);
var apelido = result.Atleta[0].apelido;
var foto = result.Atleta[0].foto;
var clube_nome = result.Atleta[0].clube_nome;
var posição = result.Atleta[0].posicao;
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear()
var headerRow = ['apelido','foto','clube_nome','posição'];
sheet.appendRow(headerRow);
for(var i=0;i<result[0].Atleta;i++){
var row = [result.Atleta[i].apelido,result.Atleta[i].foto,result.Atleta[i].clube_nome,result.Atleta[i].posicao];
SpreadsheetApp.getActiveSheet().appendRow(row);
}
}
data is an array, so you need to access the element first:
var apelido = result[0].Atleta.apelido;
I think you're trying to print every player to spreadsheet, but what you've written is only looking at one of the players. Please first look at the data returned by the API and understand its structure. Looks something like this:
[
{
"Atleta": {
"atleta_id": 68952,
"nome": "Mário Sérgio Santos Costa",
"apelido": "Marinho",
"foto": "https://s.glbimg.com/es/sde/f/2019/05/30/cd8a7f9b0744e105efa0a0c572d37d6f_FORMATO.png",
"preco_editorial": 5
},
"escalacoes": 996124,
"clube": "SAN",
"clube_nome": "Santos",
"clube_id": 277,
"escudo_clube": "https://s.glbimg.com/es/sde/f/organizacoes/2014/04/14/santos_60x60.png",
"posicao": "Atacante",
"posicao_abreviacao": "ATA"
}
]
Once you understand the data, then consider this modified script, which uses batch operations to run much more quickly.
function Cartola() {
var url = 'https://api.cartolafc.globo.com/mercado/destaques';
var response = UrlFetchApp.fetch(url);
var results = JSON.parse(response.getContentText());
var table = [['apelido','foto','clube_nome','posição']];
for (var i = 0; i < results.length; i++) {
var r = results[i];
var apelido = r.Atleta.apelido;
var foto = r.Atleta.foto;
var clube_nome = r.clube_nome;
var posição = r.posicao;
table.push([apelido, foto, clube_nome, posição]);
}
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear().getRange(1, 1, table.length, table[0].length).setValues(table);
}

Exporting sheet data to JSON file

This is my simple Sheet divided by freezed rows to Head and Body:
And this is what the final output(json) should look like:
{
"3":{
"AB1":{
"A2":"A3",
"B2":"B3"
},
"C1":{
"C2":"C3"
}
},
"4":{
"AB1":{
"A2":"A4",
"B2":"B4"
},
"C1":{
"C2":"C4"
}
},
...
}
My code look like this:
function doGet() {
var SpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = SpreadSheet.getSheets()[1];
var FirstRow = 1;
var FirstColumn = 1;
var LastRow = Sheet.getLastRow();
var LastColumn = Sheet.getLastColumn();
var FrozenRows = Sheet.getFrozenRows();
var FrozenColumns = Sheet.getFrozenColumns();
var HeadRange = Sheet.getRange(FirstRow, FirstColumn + FrozenColumns, FrozenRows - FirstRow + 1, LastColumn - FrozenColumns); // A1:C2
var HeadData = HeadRange.getValues(); // [[AB1, , C1], [A2, B2, C2]]
var BodyRange = Sheet.getRange(FirstRow + FrozenRows, FirstColumn + FrozenColumns, LastRow - FrozenRows, LastColumn - FrozenColumns); // A3:C6
var BodyData = BodyRange.getValues(); // [[A3, B3, C3], [A4, B4, C4], [A5, B5, C5], [A6, B6, C6]]
and will end with this:
var OutputData = ContentService.createTextOutput(JSON.stringify(InputData)).setMimeType(ContentService.MimeType.JSON);
return OutputData;
and now my problems :), first problem is, how get value from empty merged cell, when don't know his range, only know other side when know range and want value
for (var i = 0; i < HeadData[0].length; i++) {
var Category = HeadData[0][i];
var CellValue = (RangeCell.isPartOfMerge() ? RangeCell.getMergedRanges()[0].getCell(1,1) : RangeCell).getValue();
Second problem is, how put code together when want start json with number of row data, then category, subcategory and last with item data:
var Obj = {};
for (var i = 1; i <= ItemsRange.getNumRows(); i++) {
var ItemIndex = ItemsRange.getCell(i,1).getRowIndex();
for (var j = 0; j < BodyData.length; j++) {
for (var k = 0; k < BodyData[j].length; k++) {
var ItemCell = BodyData[j][k];
}
}
Obj[ItemIndex] = {};
}
In this case, how about the following flow?
Retrieve values from Spreadsheet.
This is from your script.
Recreate header rows.
Create the result object.
Modification points:
In this modification, at first, the header data is created. The merged ranges can be retrieve by getMergedRanges(). I created the header data using this.
When your sample Spreadsheet is used, HeadData becomes [[AB1, AB1, C1], [A2, B2, C2]] from [[AB1, , C1], [A2, B2, C2]].
In your case, it has already been found that the result object is the nested object with 3 levels. I think that this can be used.
Modified script:
function doGet() {
// 1. Retrieve values from Spreadsheet. This is from your script.
var SpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = SpreadSheet.getSheets()[1];
var FirstRow = 1;
var FirstColumn = 1;
var LastRow = Sheet.getLastRow();
var LastColumn = Sheet.getLastColumn();
var FrozenRows = Sheet.getFrozenRows();
var FrozenColumns = Sheet.getFrozenColumns();
var HeadRange = Sheet.getRange(FirstRow, FirstColumn + FrozenColumns, FrozenRows - FirstRow + 1, LastColumn - FrozenColumns); // A1:C2
var HeadData = HeadRange.getValues(); // [[AB1, , C1], [A2, B2, C2]]
var BodyRange = Sheet.getRange(FirstRow + FrozenRows, FirstColumn + FrozenColumns, LastRow - FrozenRows, LastColumn - FrozenColumns); // A3:C6
var BodyData = BodyRange.getValues(); // [[A3, B3, C3], [A4, B4, C4], [A5, B5, C5], [A6, B6, C6]]
// 2. Recreate header rows.
Sheet.getRange(1, 1, 1, Sheet.getLastColumn()).getMergedRanges().forEach(r => {
let temp = "";
for (let i = r.getColumn(); i <= r.getNumColumns(); i++) {
if (HeadData[0][i - 1].toString() != "") temp = HeadData[0][i - 1];
}
for (let i = r.getColumn(); i <= r.getNumColumns(); i++) {
HeadData[0][i - 1] = temp;
}
});
// 3. Create the result object.
const InputData = BodyData.reduce((o1, r, i) => {
o1[i + FirstRow + FrozenRows] = r.reduce((o2, c, j) => {
const t1 = HeadData[0][j];
const t2 = {[HeadData[1][j]]: c};
return Object.assign(o2, {[t1]: o2[t1] ? Object.assign(o2[t1], t2) : t2});
}, {});
return o1;
}, {});
var OutputData = ContentService.createTextOutput(JSON.stringify(InputData)).setMimeType(ContentService.MimeType.JSON);
return OutputData;
}
Result:
When your sample Spreadsheet is used, the value of InputData is as follows.
{
"3": {
"AB1": {
"A2": "A3",
"B2": "B3"
},
"C1": {
"C2": "C3"
}
},
"4": {
"AB1": {
"A2": "A4",
"B2": "B4"
},
"C1": {
"C2": "C4"
}
},
"5": {
"AB1": {
"A2": "A5",
"B2": "B5"
},
"C1": {
"C2": "C5"
}
},
"6": {
"AB1": {
"A2": "A6",
"B2": "B6"
},
"C1": {
"C2": "C6"
}
}
}
Note:
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Please be careful this.
When your actual situation is largely different from your sample Spreadsheet in your question, this modified script might not work. So please be careful this.
Please use this modified script with V8.
References:
getMergedRanges()
reduce()
Object.assign()

JSON to Google sheet --> Strange Columns + Everything in one cell

So far i managed to get a connection to a secure JSON. What i dont get to work is the data nice in columns. Plus in the metadata there a nice "labels" but now i get weird column names. Date: Streetname for example.
I have tried a couple of questions on this site. but i dont get it to work.
This is my JSON data (sorry it is in dutch)(so as you can see Project: Zipcode....?):
{
"skip": 0,
"take": 100,
"rows": [
{
"Volgnummer": 1,
"Omschrijving": "Projectnaam",
"Omschrijving_2": "Productnaam",
"Trailercodering": "productnaam-01",
"Omschrijving_3": "Warehouse",
"Datum_laden": "3 juni 2019",
"Tijdstip_laden": "1600 - 1800",
"Datum_aankomst_lossen": "4 juni 2019",
"Tijdstip_lossen": "0800 - 1000",
"Naam": "Transporteur",
"Datum": "Straat"
"Herkomst": huisnummer,
"Navigatie_transport": null,
"Project": "6644 KX",
"Woonplaats": "Ewijk",
"Land": "Nederland"
},
And this is my Google-Script code so far:
function pullJSON1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getActiveSheet();
var url= "https://the-url.com");
var headers = {
"Authorization": "AfasToken "+
Utilities.base64Encode(<token><version>1</version><data> hier de
token</data></token>)
};
var options = {
"method" : "get",
"headers" : headers
};
var response = UrlFetchApp.fetch(url,options); // get feed
var dataAll = JSON.parse(response.getContentText());
var rows = [Object.keys(dataAll)]; // Retrieve headers.
var temp = [];
for (var i = 0; i < rows[0].length; i++) {
temp.push(dataAll[rows[0][i]]); // Retrieve values.
}
rows.push(temp);
sheet.getRange(1,1,rows.length,rows[0].length).setValues(rows);
// Put values to Spreadsheet.
}
sheet output
(source: imggmi.com)
Can someone help?
I would this rearranged in columns. Also my output in the sheet gives me 1 entry but there a 356 enterys in total.
Great thanks,
Remco
Do you need the "skip", "take" variables? These don't fit with the tabular data, plus they seem to be part of a pagination system (in which case you should probably hide it from the results). Below I provide code to put the actual rows into your sheet:
function pullJSON1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getActiveSheet();
var url = "https://the-url.com";
var headers = {
"Authorization": "AfasToken " + Utilities.base64Encode("<token><version>1</version><data> hier de token</data></token>");
};
var options = {
"method" : "get",
"headers" : headers
};
var response = UrlFetchApp.fetch(url, options); // get feed
var dataAll = JSON.parse(response.getContentText());
var dataRows = dataAll['rows'];
var rowHeaders = Object.keys(dataRows[0]);
var rows = [rowHeaders]; // Retrieve headers.
for (var i = 0; i < dataRows.length; i++) {
var rowData = [];
for (var j = 0; j < rowHeaders.length; j++) {
rowData.push(dataRows[i][rowHeaders[j]]); // Retrieve values.
}
rows.push(rowData);
}
sheet.getRange(1,1,rows.length,rows[0].length).setValues(rows);
// Put values to Spreadsheet.
}

How do i get a JSON file out of my SpreadSheet

I want to get a JSON out my spreadsheet that looks like this() and to extract a JSON file like this:
[{ "module": "ModuleA",
"Questions" : [{
"Question": "xxxx",
"Answers" : ["1","2","3"],
"right answer" : "2",
}
]
This is what i have by now but its not in the coreect hierarchy
function doGet(){
var ss = SpreadsheetApp.openById('14-vl75N4mAv9FdZNHIhX_lhtQ-XY17lOvEnLIjiSwDc');
var result={};
var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetA')
.getDataRange()
.getValues();
var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetB')
.getDataRange()
.getValues();
result.sheetA = makeObject(sheetA);
result.sheetB = makeObject(sheetB);
Logger.log(result.sheetA)
//return ContentService.createTextOutput(JSON. stringify(result))
//.setMimeType(ContentService.MimeType.JSON);
}
function makeObject(multiArr) {
var obj = {};
var headers = multiArr.shift()
for(var i = 0; i< headers.length; i++){
obj[headers[i]]= multiArr.map(function(app){
return app[i];
});
}
return obj;
}
What about this solution?
function doGet(){
var ss = SpreadsheetApp.openById('14-vl75N4mAv9FdZNHIhX_lhtQ-XY17lOvEnLIjiSwDc');
var result={};
var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetA')
.getDataRange()
.getValues();
var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetB')
.getDataRange()
.getValues();
result.sheetA = makeObject(sheetA);
result.sheetB = makeObject(sheetB);
Logger.log(makeObject(sheetA))
}
function makeObject(multiArr) {
var obj = [];
for(var i=1;i<multiArr.length;i++)
{
obj.push( {
"Question": multiArr[i][1],
"Answers" : [multiArr[i][2],multiArr[i][3],multiArr[i][4]],
"right answer" : multiArr[i][5],
}
)
}
var myJSON=[{ "module": multiArr[1][0],
"Questions" : obj
}]
return JSON.stringify(myJSON);
}
You can push into an array your data formatted according to the hierarchy of
your choice, populate it within a loop with the contents of each row
in your sheet and then JSON.stringify it.
This works as above provided you have only one module per sheet. Otherwise, you need to implement an additional function which would detect in which row ModuleA ends and ModuleB starts.

Trying to view sheet after opening spreadsheet with openById() in google sheets

I have a Google Sheets that has D3.JS, i'm trying to use a specific sheet in the spreadsheet file, since that's where the table is located for the graph i'm trying to show. So far, the openById works but still is unable to locate the specific sheet in the spreadsheet.
function getChartData() {
var ss = SpreadsheetApp.openById("some id");
var sheet = ss.getActiveSheet();
var headings = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
.map(function(heading) {
return heading.toLowerCase();
});
...
}
EDIT: I've tried the following code changes below:
function getChartData() {
var ss = SpreadsheetApp.openById("some id");
var sheet = ss.getSheetByName("Tracker1");
// new code above
var headings = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
.map(function(heading) {
return heading.toLowerCase();
});
Logger.log(headings);
var values = sheet.getRange(3, 1, sheet.getLastRow()-2, sheet.getLastColumn()).getValues();
var data = [];
for (var i = 0; i < values.length; i++) {
var obj = {};
for (var j = 0; j < values[i].length; j++) {
obj[headings[j]] = values[i][j];
}
data.push(obj);
}
return data;
}
EDIT 10/2/18 11:00 PM : I'm still getting null, no error messages, no chart showing in app. I'm sure I'm doing something wrong, even without having getActiveSheet();