skip to Main Content

Given a json file with nested objects (not arrays) like:

{
    "data": {
        "UniqueName1": {
            "name": "Bob",
            "title": "the man"
        },
        "UniqueOtherName": {
            "name": "Joe",
            "title": "the myth"
        },
        "SuperUniqueName": {
            "name": "Steve",
            "title": "the legend"
        }
    }
}

Using Apps Script, how do I iterate through each unique sub-object to read the common properties therein?

function importLoLChampions() {

  var files = DriveApp.getFilesByName("championFull.json");
  if (files.hasNext()) {
  var file = files.next();
  var jsonString = file.getBlob().getDataAsString();
  var jsonParsed = JSON.parse(jsonString);

  //I can do this:
  Logger.log(jsonParsed.data.UniqueName1.name);
  Logger.log(jsonParsed.data.UniqueOtherName.name);
  Logger.log(jsonParsed.data.SuperUniqueName.name);

  //But I want to do this:
  for(var champion in jsonParsed.data ) 
  {
      Logger.log(champion); //ok so far cause it's treating champion as a string
      for(var championData in champion) //Doesn't work 
      {
        //Champion is treated as a string value, 
        //i.e. seems to have lost object awareness
        Logger.log(championData.name); //output: null
      }
      
  }
  //Or this:
  for(var i=0; i<jsonParsed.data.length); i++)
  {
      Logger.log(jsonParsed.data[i].name); 
      //Fails, treats jsonParsed.data[i] as a string
      //and not an object
  }
    

}

I’ve been struggling with this for a few hours, can’t find a good answer.
Is there a way to retrieve jsonParsed.data[i] as an object?
Or another way to step through each sub-object to access the keys/values within?

3

Answers


  1. To traverse nested JSON objects with distinct names in Google Apps Script, recursion can be employed effectively. Below is a detailed guide:

    Sample JSON

    {
      "person": {
        "name": "John",
        "age": 30,
        "address": {
          "street": "123 Main St",
          "city": "Anytown",
          "postalCode": "12345"
        },
        "contacts": {
          "email": "[email protected]",
          "phone": "555-1234"
        }
      }
    }
    

    Code for Iterating Through Nested JSON
    The following code demonstrates this process:

    function traverseNestedJSON(jsonObject) {
      for (var key in jsonObject) {
        if (jsonObject.hasOwnProperty(key)) {
          if (typeof jsonObject[key] === 'object' && jsonObject[key] !== null) {
            // Recursively invoke the function for nested objects
            console.log("Entering nested object: " + key);
            traverseNestedJSON(jsonObject[key]);
          } else {
            // Output the key and value for non-object properties
            console.log(key + ": " + jsonObject[key]);
          }
        }
      }
    }
    
    function executeExample() {
      var json = {
        "person": {
          "name": "John",
          "age": 30,
          "address": {
            "street": "123 Main St",
            "city": "Anytown",
            "postalCode": "12345"
          },
          "contacts": {
            "email": "[email protected]",
            "phone": "555-1234"
          }
        }
      };
    
      traverseNestedJSON(json);
    }
    

    Explanation:

    1. Iterate through keys: Utilize a for...in loop to go through the keys of the JSON object.
    2. Verify property ownership: Employ hasOwnProperty to confirm that you are not accessing properties from the prototype chain.
    3. Identify nested objects: If the value associated with a key is an object, recursively call the function.
    4. Process non-object values: Directly log or handle the key-value pairs.

    Output:

    Entering nested object: person
    name: John
    age: 30
    Entering nested object: address
    street: 123 Main St
    city: Anytown
    postalCode: 12345
    Entering nested object: contacts
    email: [email protected]
    
    Login or Signup to reply.
  2. You can use a for...of statement with Object.entries() to iterate over the collection of objects. And you can also leverage destructuring assignment to make the things a little more readable.

    Given:

    var json = {
        "data": {
            "UniqueName1": {
                "name": "Bob",
                "title": "the man"
            },
            "UniqueOtherName": {
                "name": "Joe",
                "title": "the myth"
            },
            "SuperUniqueName": {
                "name": "Steve",
                "title": "the legend"
            }
        }
    }
    

    Then you can do this:

    function iterateOverEntries(json) {
        for (const [uniqueName, { name, title }] of Object.entries(json.data)) {
            console.log(JSON.stringify({
                uniqueName,
                name,
                title
            }, undefined, 4));
        }
    }
    

    Note: Google Apps Script now supports modern Javascript, so try to use let and/or const instead of var, console.log instead of Logger.log, etc.

    Login or Signup to reply.
  3. One of the earlier answers noted:

    Google Apps Script now supports modern Javascript, so try to use let and/or const instead of var, console.log instead of Logger.log, etc.

    If that’s the case, then a function I use often, might make this simpler.

    const pathEntries = (o, path = []) => [
      ... (path.length > 0 ? [[path, o]] : []),
      ... (Object (o) === o ? Object.entries(o).flatMap (
            ([k, v]) => pathEntries(v, [...path, Array.isArray(o) ? Number(k) : k])
          ) : [])
    ]
    

    Applied to your object it would yield:

    [
        [ ["data"],                             __original object here__             ],
        [ ["data", "UniqueName1"],              {name: "Bob", title: "the man"}      ],
        [ ["data", "UniqueName1", "name"],      "Bob"                                ],
        [ ["data", "UniqueName1", "title"],     "the man"                            ],
        [ ["data", "UniqueOtherName"],          {name: "Joe", title: "the myth"}     ],
        [ ["data", "UniqueOtherName", "name"],  "Joe"                                ],
        [ ["data", "UniqueOtherName", "title"], "the myth"                           ],
        [ ["data", "SuperUniqueName"],          {name: "Steve", title: "the legend"} ]
        [ ["data", "SuperUniqueName", "name"],  "Steve"                              ],
        [ ["data", "SuperUniqueName", "title"], "the legend"                     ]
    ]
    

    And then you could use the resulting array of path/value pairs to log output or to build something else.

    const pathEntries = (o, path = []) => [
      ... (path.length > 0 ? [[path, o]] : []),
      ... (Object (o) === o ? Object.entries(o).flatMap (
            ([k, v]) => pathEntries(v, [...path, Array.isArray(o) ? Number(k) : k])
          ) : [])
    ]
    
    const data = {data: {UniqueName1: {name: "Bob", title: "the man"}, UniqueOtherName: {name: "Joe", title: "the myth"}, SuperUniqueName: {name: "Steve", title: "the legend"}}}
    
    console.log(pathEntries(data))
    .as-console-wrapper {max-height: 100% !important; top: 0}
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search