Populating and formatting JSON into a Google Sheet

Tags: , , , ,



Thank you in advance to anyone that is able to help me on this. I have been trying for days to make this work, and just don’t know enough about this to figure it out using examples.

I have developed an Android app that places orders in a Realtime Database. Each order has its own ID that is generated by the app. I would like each order to display in a row when I run the code and go into the correct column based on the column header. I have found this example that seems to fit my need exactly (same JSON structure), but does not work when I try to repurpose. Here is what I have:

function chunkArray(myArray, chunk_size){
    var index = 0;
    var arrayLength = myArray.length;
    var tempArray = [];
    
    for (index = 0; index < arrayLength; index += chunk_size) {
        myChunk = myArray.slice(index, index+chunk_size);
        // Do something if you want with the group
        tempArray.push(myChunk);
    }

    return tempArray;
}

function flatten(arrayOfArrays){
  return [].concat.apply([], arrayOfArrays);
}


function insertJSON(){
  
  // this puts the keys in the correct place
  var aOneName = "id";
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("orders");
  var fileURL = "<-RT DB Link ->";
  var res = UrlFetchApp.fetch(fileURL,{'muteHttpExceptions': true});
  var content = res.getContentText();
  var json = JSON.parse(content);
  var rows = [Object.keys(json)]; // Retrieve entry column.
  var toRows = rows[0].length;
  var toRows = toRows + 1;
  var rowsflate = flatten(rows);
  var rowstocols  = chunkArray(rowsflate, 1);
  sheet.getRange("A2:A" + toRows).setValues(rowstocols); // sets column of IDs
  sheet.getRange(1, 1).setValue(aOneName); // A1 name
  var headers = json[rows[0][2]];
  var getHeaders = [Object.keys(headers)];
  sheet.getRange(1,2,getHeaders.length,getHeaders[0].length).setValues(getHeaders); // Put values to Spreadsheet.
  content
  var content = [];
  var temp = [];
  for (var i = 0; i < rows[0].length; i++) {
    var temp2 = [Object.values(json[rows[0][i]])];// Retrieve values to be split.
    Logger.log(temp2);
    content.push(flatten(temp2));
  }
  var columncount1= rows[0].length;
  var columncount2 = getHeaders[0].length;
  sheet.getRange(2,2,columncount1,columncount2).setValues(content); // Put values to Spreadsheet.
}

The code works to pull the JSON data and correctly puts the keys for each order in column A starting at A2. After that however there are 2 problems when using this code:

  1. The headers are overwritten and the order of them is changed (alphabetized) – this is not a deal breaker and can reorder around this if needed, but ideally when placing the values in the cells it will look at the column header (same as the value header in the JSON) and place the correct values in the cells. Expected: What the spreadsheet should look like Actual: Reordering when code is run

  2. Object.values throws the error: TypeError: Cannot find function values in object function Object() { [native code for Object.Object, arity=1] }. (line 152, file "Code"). I have replaced this with .keys and attempted to use .map but then receive an error message below in the line sheet.getRange(2,2,columncount1,columncount2).setValues(content);: "The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 19. (line 161, file "Code")"

Here is the JSON

{
   "12":{
      "orderAddress":"address 1",
      "orderDelivered":"No",
      "orderDent":2,
      "orderDish":0,
      "orderEmail":"Not Provided",
      "orderId":"12",
      "orderLatLong":"Not Captured",
      "orderLend":1,
      "orderName":"Name 1",
      "orderPaid":"No",
      "orderPhone":"Phone 1",
      "orderSans":0,
      "orderSign":8,
      "orderText":6,
      "orderTint":0,
      "orderTotal":17,
      "orderTotalCost":200,
      "orderTrain":0,
      "orderTree":0
   },
   "13":{
      "orderAddress":"address 2",
      "orderDelivered":"No",
      "orderDent":0,
      "orderDish":1,
      "orderEmail":"Not Provided",
      "orderId":"13",
      "orderLatLong":"Not Captured",
      "orderLend":1,
      "orderName":"Name 2",
      "orderPaid":"Yes",
      "orderPhone":"Phone 2",
      "orderSans":0,
      "orderSign":0,
      "orderText":0,
      "orderTint":0,
      "orderTotal":27,
      "orderTotalCost":40,
      "orderTrain":0,
      "orderTree":0
   },
   "-MMIu9hQrxlZNs91nl2M":{
      "orderAddress":"address 3",
      "orderDelivered":"Yes",
      "orderDent":0,
      "orderDish":0,
      "orderEmail":"Not Provided",
      "orderId":"-MMIu9hQrxlZNs91nl2M",
      "orderLatLong":"Not Captured",
      "orderLend":1,
      "orderName":"Name 3",
      "orderPaid":"Yes",
      "orderPhone":"Phone 3",
      "orderSans":0,
      "orderSign":0,
      "orderText":0,
      "orderTint":0,
      "orderTotal":1,
      "orderTotalCost":12,
      "orderTrain":0,
      "orderTree":0
   }
}

Again, any direction on this would be greatly appreciated!

Answer

I believe your goal as follows.

  • You want to retrieve the values from json and put the parsed values with the order of header of "id", "orderId", "orderName", "orderAddress", "orderPhone", "orderEmail", "orderLatLong", "orderDent", "orderLend", "orderTrain", "orderDish", "orderSans", "orderTint", "orderText", "orderSign", "orderTree", "orderTotal", "orderTotalCost", "orderPaid", "orderDelivered".
  • You want to achieve this using Google Apps Script.

Modification points:

  • At JSON object, the order of keys are not guaranteed. So in your case, I think that giving the ordered header values is suitable.
  • By declaring the header values as an array, I would like to propose the following flow.
    1. Declare the header values.
    2. Create an array for putting to Spreadsheet.
    3. Put the created array to Spreadsheet.

Whe above points are reflected to your script, it becomes as follows.

Modified script:

Please modify your script as follows.

From:
var rows = [Object.keys(json)]; // Retrieve entry column.
var toRows = rows[0].length;
var toRows = toRows + 1;
var rowsflate = flatten(rows);
var rowstocols  = chunkArray(rowsflate, 1);
sheet.getRange("A2:A" + toRows).setValues(rowstocols); // sets column of IDs
sheet.getRange(1, 1).setValue(aOneName); // A1 name
var headers = json[rows[0][2]];
var getHeaders = [Object.keys(headers)];
sheet.getRange(1,2,getHeaders.length,getHeaders[0].length).setValues(getHeaders); // Put values to Spreadsheet.
content
var content = [];
var temp = [];
for (var i = 0; i < rows[0].length; i++) {
  var temp2 = [Object.values(json[rows[0][i]])];// Retrieve values to be split.
  Logger.log(temp2);
  content.push(flatten(temp2));
}
var columncount1= rows[0].length;
var columncount2 = getHeaders[0].length;
sheet.getRange(2,2,columncount1,columncount2).setValues(content); // Put values to Spreadsheet.
To:
// 1. Declare the header values.
const header = ["id", "orderId", "orderName", "orderAddress", "orderPhone", "orderEmail", "orderLatLong", "orderDent", "orderLend", "orderTrain", "orderDish", "orderSans", "orderTint", "orderText", "orderSign", "orderTree", "orderTotal", "orderTotalCost", "orderPaid", "orderDelivered"];

// 2. Create an array for putting to Spreadsheet.
const values = Object.entries(json).map(([k, v]) => {
  v.id = k;
  return header.map(h => v[h]);
});
values.unshift(header);  // When you want to add the header, please use this.

// 3. Put the created array to Spreadsheet.
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);

Note:

  • When you use this script, please enable V8 runtime.

Reference:



Source: stackoverflow