admin管理员组

文章数量:1123699

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?

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?

Share Improve this question edited 18 hours ago Wicket 38k9 gold badges77 silver badges189 bronze badges asked yesterday user645379user645379 255 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 1

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.

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]

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}

Thank you everyone, all were relevant and helpful! The AddOnDepot's response is spot on. For my incredibly unsavvy code, I ended up using something like:

for (const [dataKey, peopleValues] of Object.entries(jsonParsed.data)) {
  Logger.log(`${dataKey}`);
  Logger.log(peopleValues.name);
  Logger.log(peopleValues.title);
  /* And was able to apply the same concept to access deeper nested values!
  for( const [deeperNestedKeys, deeperData] of Object.entries(peopleValues))
  {
      Logger.log(deeperData.otherValue);
  }
  */
}

My first tip off was actually from an old stackoverflow post that I didn't fully understand at first, so credit also to: https://stackoverflow.com/a/62735012/645379

本文标签: javascriptHow to iterate through nested json objects with unique names in Apps ScriptStack Overflow