-2

I am working to get values from deeply nested object. The data and expected output are below. I got this data like below from request of API.

I have to use this script at Google Apps Script. So please note I cannot use ECMAScript6.

Object

var obj = {
  "key1": [
    {
      "key2": [
        {
          "key3": {
            "key4": {
              "key5": [
                {
                  "key6": "value6"
                },
                {},
                {
                  "key7": {
                    "key8": "value8"
                  }
                }
              ]
            }
          }
        },
        {
          "key3": {
            "key4": {
              "key5": [
                {
                  "key6": "value6"
                },
                {
                  "key7": {
                    "key8": "value8"
                  }
                },
                {}
              ]
            }
          }
        },
        {
          "key3": {
            "key5": "value5"
          }
        }
      ]
    },
    {
      "key2": [
        {
          "key3": {
            "key4": {
              "key5": [
                {
                  "key6": "value6"
                },
                {
                  "key7": {
                    "key8": "value8"
                  }
                }
              ]
            }
          }
        },
        {
          "key3": {
            "key4": {
              "key5": [
                {
                  "key6": "value6"
                },
                {},
                {
                  "key7": {
                    "key8": "value8"
                  }
                },
                {}
              ]
            }
          }
        },
        {
          "key3": {
            "key5": "value5"
          }
        }
      ]
    }
  ]
};

Expected output

I want values of "key8".

value8
value8
value8
value8

My current script

for (var i in obj.key1) {
  for (var j in obj.key1[i].key2) {
    for (var k in obj.key1[i].key2[j].key3.key4.key5[k]) {
      Logger.log(obj.key1[i].key2[j].key3.key4.key5[k].key7.key8)
    }
  }
}

Error message

TypeError: Cannot read property "key5" from undefined.

This error is at

for (var k in json.key1[i].key2[j].key3.key4.key5[k]) {

My questions are

  • What is reason of error?
  • How modify should I my script to get values of "key8"?

Updated

I got 2 solutions of my question.

One is

var result = [];
for (var i in obj.key1) {
  for (var j in obj.key1[i].key2){
    if (obj.key1[i].key2[j].key3.key4) {
      for (var k in obj.key1[i].key2[j].key3.key4.key5) {
        if (obj.key1[i].key2[j].key3.key4.key5[k].key7) {
          result.push(obj.key1[i].key2[j].key3.key4.key5[k].key7.key8);
        }
      }
    } else {
      continue;
    }
  }
}
Logger.log(result) // >>> [value8, value8, value8, value8]

https://jsfiddle.net/Lxa8tsfb/

Another is

var result = function () {
  var result = [];
  (function traverse(obj) {
    if (Array.isArray(obj)) {
      obj.forEach(traverse);
    } else if (typeof obj === 'object') {
      Object.keys(obj).forEach(function(key) {
        if (key === 'key8') {
          result.push(obj[key]);
        } else {
          traverse(obj[key]);
        }
      });
    }
  }(obj));
  return result;
}();
Logger.log(result) // >>> [value8, value8, value8, value8]

https://jsfiddle.net/ffuuur0L/

1st one is my answer. 2nd one is an answer by @Petr. My answer can use only when users know the structure of object. Petr's answer can use when users know the key. I think Petr's answer is useful. So I accepted Petr's answer.

Elsa
  • 654
  • 1
  • 8
  • 21

1 Answers1

0

You can use recursion here, something like this:

function traverse(json) {
    if (Array.isArray(json)) {
        json.forEach(traverse);
    } else if (typeof json === 'object') {
        Object.keys(json).forEach(function(key) {
            if (key === 'key8') {
                console.log(json[key]);
            } else {
               traverse(json[key]);
            }
        });
    }
};

traverse(json);

This code is obviously imperfect, you might want to make key8 a parameter and wrap this into some method with a better name, but it works.

Petr
  • 5,999
  • 2
  • 19
  • 25
  • Thank you for taking your time. I could find values at ``console.log(json[key])``. Can you return all values to outside of ``traverse(json)``? – Elsa Nov 15 '17 at 08:39
  • @NinaScholz: `typeof json === 'object'` has that covered. This answer will not traverse strings. – Cerbrus Nov 15 '17 at 08:45
  • @Cerbrus, right but no not `null` check. – Nina Scholz Nov 15 '17 at 08:46
  • The missing null check doesn't validate your previous comment. That's completely different. – Cerbrus Nov 15 '17 at 08:47
  • Petr, add this at the start of your function: `if(!json)return;` – Cerbrus Nov 15 '17 at 08:48
  • I got 2 solutions. But I think your answer is better than mine. I accepted your answer. Thank you very much. I have one question. Your answer is your original? If you refered to other user's answer, can I ask you about the URL? I want to upvote it. – Elsa Nov 20 '17 at 06:15