4

I have following file1 json:

{
  "name": "eye",
  "attributes": [
    {
      "name": "Width",
      "value": "1920"
    },
    {
      "name": "Height",
      "value": "1080"
    },
    {
      "name": "WinKeyMapping",
      "value": "leftwin"
    }
  ],
  "starts": [
    {
      "name": "step1",
      "attributeList": [
        {
          "name": "Command",
          "value": "bash"
        },
        {
          "name": "Test",
          "value": "none"
        }
      ]
    }
  ]
}

and following filter:

$ jq '.starts[].attributeList[]|select(.name=="Command")' file1
{
  "name": "Command",
  "value": "bash"
}
$

how could I get whole structure to this selection?

expected output:

{
  "starts": [
    {
      "attributeList": [
        {
          "name": "Command",
          "value": "bash"
        }
      ]
    }
  ]
}

3 Answers 3

2

Straightforwardly with jq:

jq '{ starts: [ { attributeList: (.starts[].attributeList 
                                  | map(select(.name == "Command"))) }] }' file.json

The output:

{
  "starts": [
    {
      "attributeList": [
        {
          "name": "Command",
          "value": "bash"
        }
      ]
    }
  ]
}
3
  • thank you. would it be feasible to "extract" from a huge json all such paths+attributes and save each into separate file named related with the path+attribname - e.g. for example above: starts.attributeList.Command.json ? Commented Mar 10, 2018 at 13:08
  • @DonJ, welcome, your new description is the case for another question Commented Mar 10, 2018 at 13:30
  • I am trying to collect all attributes which are modified by WebUI (for future usage via REST API). For this case, I GET default json (configuration) and after that did changes via WebUI of the configuration and again GET changed configuration. Thanks to you I have already extracted all attributes from the two big json files to single json files, compared them one by one and now I know which ones were modified (there are tens). do you maybe know how to merge this modified now back to sigle file so I can use it at one REST API PUT command? Commented Mar 10, 2018 at 15:01
0

Here are two options to obtain your desired output.

You can delete the keys you don't want:

jq 'del(.attributes, .name) | 
  .starts[].attributeList = map(.[].attributeList[] | select(.name == "Command"))'

Or you can select only the key(s) you do want:

jq 'to_entries | map(select(.key == "starts")) | from_entries | 
  .starts[].attributeList = map(.[].attributeList[] | select(.name == "Command"))'

Both give the same result. Also if you wanted starts and ends in the latter case, you could just add additional or statements: map(select((.key == "starts") or (.key == "ends"))).

0

A more generic approach with jq:

def pick_out(q): path(q) as $path | ($path | length) as $length |
    delpaths(
        [
            paths(..) |
            select(length <= $length and $path[0:length] != . )
        ]
    );

This is a jq function that deletes all the paths of the document that does not lie anywhere on the path of the given argument, which may be a select() call.

Saving this in pick_out.jq, we may use it like so:

jq 'include "pick_out";
    pick_out(
        .starts[].attributeList[] | select(.name == "Command")
    )' file.json

The output:

{
  "starts": [
    {
      "attributeList": [
        {
          "name": "Command",
          "value": "bash"
        }
      ]
    }
  ]
}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.