3

I'm trying to get the value of eth0 nested inside this JSON object

"addresses": {
  "eth0": [
    "10.0.3.188"
  ]
},

I was using underscore.js to simplify the process

var _ = require('underscore')._;

var jsonData = {
    "plays": [{
        "play": {
            "id": "d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",
            "name": "lxc"
        },
        "tasks": [{
                "hosts": {
                    "lxc.server.com": {
                        "_ansible_no_log": false,
                        "_ansible_parsed": true,
                        "changed": true,
                        "cmd": "lxc copy base \"bar69\"",
                        "delta": "0:00:01.417533",
                        "end": "2017-01-10 18:01:28.692981",
                        "invocation": {
                            "module_args": {
                                "_raw_params": "lxc copy base \"bar69\"",
                                "_uses_shell": true,
                                "chdir": null,
                                "creates": null,
                                "executable": null,
                                "removes": null,
                                "warn": true
                            },
                            "module_name": "command"
                        },
                        "rc": 0,
                        "start": "2017-01-10 18:01:27.275448",
                        "stderr": "",
                        "stdout": "",
                        "stdout_lines": [],
                        "warnings": []
                    }
                },
                "task": {
                    "id": "297bf7b7-9ee7-4517-8763-bc3b15baa6e2",
                    "name": "clone from base"
                }
            },
            {
                "hosts": {
                    "lxc.server.com": {
                        "_ansible_no_log": false,
                        "_ansible_parsed": true,
                        "changed": true,
                        "cmd": "lxc config set \"bar69\" security.privileged true",
                        "delta": "0:00:00.053403",
                        "end": "2017-01-10 18:01:32.270750",
                        "invocation": {
                            "module_args": {
                                "_raw_params": "lxc config set \"bar69\" security.privileged true",
                                "_uses_shell": true,
                                "chdir": null,
                                "creates": null,
                                "executable": null,
                                "removes": null,
                                "warn": true
                            },
                            "module_name": "command"
                        },
                        "rc": 0,
                        "start": "2017-01-10 18:01:32.217347",
                        "stderr": "",
                        "stdout": "",
                        "stdout_lines": [],
                        "warnings": []
                    }
                },
                "task": {
                    "id": "bc63ad6f-1808-48b8-a1de-729153d2b0c5",
                    "name": "Promote to privileged ct"
                }
            },
            {
                "hosts": {
                    "lxc.server.com": {
                        "_ansible_no_log": false,
                        "_ansible_parsed": true,
                        "actions": [
                            "start"
                        ],
                        "addresses": {
                            "eth0": [
                                "10.0.3.188"
                            ]
                        },
                        "changed": true,
                        "invocation": {
                            "module_args": {
                                "architecture": null,
                                "cert_file": "/root/.config/lxc/client.crt",
                                "config": null,
                                "description": null,
                                "devices": null,
                                "ephemeral": null,
                                "force_stop": false,
                                "key_file": "/root/.config/lxc/client.key",
                                "name": "bar69",
                                "profiles": null,
                                "source": null,
                                "state": "started",
                                "timeout": 30,
                                "trust_password": null,
                                "url": "unix:/var/lib/lxd/unix.socket",
                                "wait_for_ipv4_addresses": true
                            },
                            "module_name": "lxd_container"
                        },
                        "log_verbosity": 0,
                        "old_state": "stopped"
                    }
                },
                "task": {
                    "id": "466c0da9-6cbf-4196-aea9-109218c3ed5f",
                    "name": "Start CT"
                }
            },
            {
                "hosts": {
                    "lxc.server.com": {
                        "_ansible_no_log": false,
                        "_ansible_verbose_always": true,
                        "changed": false,
                        "invocation": {
                            "module_args": {
                                "msg": [
                                    "10.0.3.188"
                                ]
                            },
                            "module_name": "debug"
                        },
                        "msg": [
                            "10.0.3.188"
                        ]
                    }
                },
                "task": {
                    "id": "978c490e-59c3-41d2-818d-ab4b557ad803",
                    "name": ""
                }
            }
        ]
    }],
    "stats": {
        "lxc.server.com": {
            "changed": 3,
            "failures": 0,
            "ok": 4,
            "skipped": 0,
            "unreachable": 0
        }
    }
}

This is what I have tried so far but no luck!

console.log(_.findKey(_.values(jsonData.tasks)));

Your help is highly appreciated

2
  • not every host will have this value? Commented Jan 10, 2017 at 23:45
  • no, not every host Commented Jan 10, 2017 at 23:46

5 Answers 5

2

You could use a few functions like _.pluck() to get the objects at key host, _.property() to see if each host object has a key addresses, .map() to get a mapping of the values, ._filter() to see if a value was returned from the mapping, etc.:

var hosts = _.pluck(jsonData.plays[0].tasks, 'hosts');
var mapping = _.map(hosts, function(host) {
    var keys = _.keys(host);
    if (_.size(keys)) {
      var nestedHost = host[_.first(keys)];
      if (_.property('addresses')(nestedHost)) {
        if (_.property('eth0')(nestedHost.addresses)) {
          return nestedHost.addresses.eth0[0];
        }
      }
    }
  });
console.log(_.filter(mapping));

See it in action in this plunker, as well as the example below:

var jsonData = {
  "plays": [{
    "play": {
      "id": "d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",
      "name": "lxc"
    },
    "tasks": [{
      "hosts": {
        "lxc.server.com": {
          "_ansible_no_log": false,
          "_ansible_parsed": true,
          "changed": true,
          "cmd": "lxc copy base \"bar69\"",
          "delta": "0:00:01.417533",
          "end": "2017-01-10 18:01:28.692981",
          "invocation": {
            "module_args": {
              "_raw_params": "lxc copy base \"bar69\"",
              "_uses_shell": true,
              "chdir": null,
              "creates": null,
              "executable": null,
              "removes": null,
              "warn": true
            },
            "module_name": "command"
          },
          "rc": 0,
          "start": "2017-01-10 18:01:27.275448",
          "stderr": "",
          "stdout": "",
          "stdout_lines": [],
          "warnings": []
        }
      },
      "task": {
        "id": "297bf7b7-9ee7-4517-8763-bc3b15baa6e2",
        "name": "clone from base"
      }
    }, {
      "hosts": {
        "lxc.server.com": {
          "_ansible_no_log": false,
          "_ansible_parsed": true,
          "changed": true,
          "cmd": "lxc config set \"bar69\" security.privileged true",
          "delta": "0:00:00.053403",
          "end": "2017-01-10 18:01:32.270750",
          "invocation": {
            "module_args": {
              "_raw_params": "lxc config set \"bar69\" security.privileged true",
              "_uses_shell": true,
              "chdir": null,
              "creates": null,
              "executable": null,
              "removes": null,
              "warn": true
            },
            "module_name": "command"
          },
          "rc": 0,
          "start": "2017-01-10 18:01:32.217347",
          "stderr": "",
          "stdout": "",
          "stdout_lines": [],
          "warnings": []
        }
      },
      "task": {
        "id": "bc63ad6f-1808-48b8-a1de-729153d2b0c5",
        "name": "Promote to privileged ct"
      }
    }, {
      "hosts": {
        "lxc.server.com": {
          "_ansible_no_log": false,
          "_ansible_parsed": true,
          "actions": [
            "start"
          ],
          "addresses": {
            "eth0": [
              "10.0.3.188"
            ]
          },
          "changed": true,
          "invocation": {
            "module_args": {
              "architecture": null,
              "cert_file": "/root/.config/lxc/client.crt",
              "config": null,
              "description": null,
              "devices": null,
              "ephemeral": null,
              "force_stop": false,
              "key_file": "/root/.config/lxc/client.key",
              "name": "bar69",
              "profiles": null,
              "source": null,
              "state": "started",
              "timeout": 30,
              "trust_password": null,
              "url": "unix:/var/lib/lxd/unix.socket",
              "wait_for_ipv4_addresses": true
            },
            "module_name": "lxd_container"
          },
          "log_verbosity": 0,
          "old_state": "stopped"
        }
      },
      "task": {
        "id": "466c0da9-6cbf-4196-aea9-109218c3ed5f",
        "name": "Start CT"
      }
    }, {
      "hosts": {
        "lxc.server.com": {
          "_ansible_no_log": false,
          "_ansible_verbose_always": true,
          "changed": false,
          "invocation": {
            "module_args": {
              "msg": [
                "10.0.3.188"
              ]
            },
            "module_name": "debug"
          },
          "msg": [
            "10.0.3.188"
          ]
        }
      },
      "task": {
        "id": "978c490e-59c3-41d2-818d-ab4b557ad803",
        "name": ""
      }
    }]
  }],
  "stats": {
    "lxc.server.com": {
      "changed": 3,
      "failures": 0,
      "ok": 4,
      "skipped": 0,
      "unreachable": 0
    }
  }
};
document.addEventListener('DOMContentLoaded', function() {
  var hosts = _.pluck(jsonData.plays[0].tasks, 'hosts');
  var mapping = _.map(hosts, function(host) {
    var keys = _.keys(host);
    if (_.size(keys)) {
      var nestedHost = host[_.first(keys)];
      if (_.property('addresses')(nestedHost)) {
        if (_.property('eth0')(nestedHost.addresses)) {
          return nestedHost.addresses.eth0[0];
        }
      }
    }
  });
  document.getElementById('console').innerHTML = _.filter(mapping);
});
<script data-require="underscore.js@*" data-semver="1.8.3" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Address(es):
<div id="console"></div>

Sign up to request clarification or add additional context in comments.

1 Comment

I updated it to use _.size() - we want to ensure the array of keys has an element before taking the first element of the keys collection. In this case there are always keys but it is possible there wouldn't be (e.g. if the hosts was an empty object ( i.e. 'hosts': {})
2

You can do this without underscore. An approach you can take is take the given property string and a task, split the property based on the deliminator (you cannot use '.' because you have dotted properties like 'lxc.server.com'), and recursively examine the object until you find the value (or not).

Note: The solutions bellow assume you want to pass a delimited property string but you can just as easily pass an array of props directly and not wrap the helper function.

Tail-cail recursive solution

var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
  
function getNestedPropHelper(obj, [first, ...rest]) {
  // base case
  if (typeof obj !== 'object' || !obj) return undefined;
 
  return rest.length === 0                   // if we only have one property
    ? obj[first]                             // return the value
    : getNestedPropHelper(obj[first], rest); // otherwise recursively return the rest
}

function getNestedProp(obj, prop, delim = '|') {
  return getNestedPropHelper(obj, prop.split(delim));
}

// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);

// get the eth0 property for each task
const props = tasks.map(task => 
  getNestedProp(task, 'hosts|lxc.server.com|addresses|eth0')
);

// log eth0 properties for each task (only the third one actually has the value)
console.log(props);

You can also do this iteratively, which should usually be faster (although not much in environments that support tail-calls):

Iterative solution

var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
  
function getNestedPropHelper(obj, props) {
  const isObject = (obj) => typeof obj === 'object' && obj;
  if (!isObject(obj)) return undefined;

  // keep extracting the properties
  for (const prop of props) {
    obj = obj[prop];
    // of we come across a non-object property before we're done, the property path is invalid
    if (!isObject(obj)) return undefined;
  }

  // if we reached this point, we found the value
  return obj;
}

function getNestedProp(obj, prop, delim = '|') {
  return getNestedPropHelper(obj, prop.split(delim));
}

// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);

// get the eth0 property for each task
const props = tasks.map(task => 
  getNestedProp(task, 'hosts|lxc.server.com|addresses|eth0')
);

// log eth0 properties for each task (only the third one actually has the value)
console.log(props);

Curried recursive solution same approach can be taken for the iterative one

You could also curry the function so you can build getters for certain property paths.

var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
  
function getNestedPropHelper(obj, [first, ...rest]) {
  // base case
  if (typeof obj !== 'object' || !obj) return undefined;
 
  return rest.length === 0                   // if we only have one property
    ? obj[first]                             // return the value
    : getNestedPropHelper(obj[first], rest); // otherwise recursively return the rest
}

function getNestedProp(prop, delim = '|') {
  const props = prop.split(delim);
  return function(obj) {
    return getNestedPropHelper(obj, props);
  }
}

// now you have a getter that will extract eth0 for any task
const getEth0 = getNestedProp('hosts|lxc.server.com|addresses|eth0');

// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);

// extract eth0 from each task
const props = tasks.map(getEth0);

// log eth0 properties for each task (only the third one actually has the value)        
console.log(props);

1 Comment

Glad to help mate :)
1

If you want to access it directly, try the following:

jsonData.plays[0].tasks[2].hosts["lxc.server.com"].addresses.eth0[0]

Edit: This was tested. The post that has tasks[3] is incorrect.

Comments

0

We use object-scan for many data processing tasks. It's powerful and fast once you wrap your head around it. Here is how you could solve your question

// const objectScan = require('object-scan');

const find = (input) => objectScan(['**.addresses.eth0[0]'], {
  abort: true,
  rtn: 'value'
})(input);

const jsonData = { plays: [{ play: { id: 'd10aae34-6713-4e14-8ad5-fa2fbf6aa2b5', name: 'lxc' }, tasks: [{ hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, changed: true, cmd: 'lxc copy base "bar69"', delta: '0:00:01.417533', end: '2017-01-10 18:01:28.692981', invocation: { module_args: { _raw_params: 'lxc copy base "bar69"', _uses_shell: true, chdir: null, creates: null, executable: null, removes: null, warn: true }, module_name: 'command' }, rc: 0, start: '2017-01-10 18:01:27.275448', stderr: '', stdout: '', stdout_lines: [], warnings: [] } }, task: { id: '297bf7b7-9ee7-4517-8763-bc3b15baa6e2', name: 'clone from base' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, changed: true, cmd: 'lxc config set "bar69" security.privileged true', delta: '0:00:00.053403', end: '2017-01-10 18:01:32.270750', invocation: { module_args: { _raw_params: 'lxc config set "bar69" security.privileged true', _uses_shell: true, chdir: null, creates: null, executable: null, removes: null, warn: true }, module_name: 'command' }, rc: 0, start: '2017-01-10 18:01:32.217347', stderr: '', stdout: '', stdout_lines: [], warnings: [] } }, task: { id: 'bc63ad6f-1808-48b8-a1de-729153d2b0c5', name: 'Promote to privileged ct' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, actions: ['start'], addresses: { eth0: ['10.0.3.188'] }, changed: true, invocation: { module_args: { architecture: null, cert_file: '/root/.config/lxc/client.crt', config: null, description: null, devices: null, ephemeral: null, force_stop: false, key_file: '/root/.config/lxc/client.key', name: 'bar69', profiles: null, source: null, state: 'started', timeout: 30, trust_password: null, url: 'unix:/var/lib/lxd/unix.socket', wait_for_ipv4_addresses: true }, module_name: 'lxd_container' }, log_verbosity: 0, old_state: 'stopped' } }, task: { id: '466c0da9-6cbf-4196-aea9-109218c3ed5f', name: 'Start CT' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_verbose_always: true, changed: false, invocation: { module_args: { msg: ['10.0.3.188'] }, module_name: 'debug' }, msg: ['10.0.3.188'] } }, task: { id: '978c490e-59c3-41d2-818d-ab4b557ad803', name: '' } }] }], stats: { 'lxc.server.com': { changed: 3, failures: 0, ok: 4, skipped: 0, unreachable: 0 } } };

console.log(find(jsonData));
// => 10.0.3.188
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

-1

you can use this code to loop on object properties .

   for (key in jsonData){
       if(key == "eth0" ){
          console.log(jsonData[key].toString())
       }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.