3

with jq, I'd like to get "name" value of blocks where "Media" attribute (under .session.attributeList) contains "node7000" string (in example json first array block matches it - there are two matching:

"value": "node7000"

"value": "node7000 and node8000"

and expected jq output would be:

"Station 17200"

[{
    "name": "Station 17200",
    "attributes": [{
            "name": "EnableLog",
            "value": "1"
        }, {
            "name": "LogFont",
            "value": "0"
        }, {
            "name": "IdleTimer",
            "value": "30"
        }
    ],
    "session": [{
            "attributeList": [{
                    "name": "Launch",
                    "value": "1"
                }, {
                    "name": "Media",
                    "value": "node7000"
                }
            ]
        }, {
            "attributeList": [{
                    "name": "Group",
                    "value": "1"
                }, {
                    "name": "RMedia",
                    "value": "1"
                }
            ]
        }, {
            "attributeList": [{
                    "name": "Launch",
                    "value": ""
                }, {
                    "name": "Media",
                    "value": "node7000 and node8000"
                }
            ]
        }
    ]
},
{
    "name": "Station 17300",
    "attributes": [{
            "name": "EnableLog",
            "value": "1"
        }, {
            "name": "LogFont",
            "value": "0"
        }, {
            "name": "IdleTimer",
            "value": "30"
        }
    ],
    "session": [{
            "attributeList": [{
                    "name": "Launch",
                    "value": "1"
                }, {
                    "name": "Media",
                    "value": "node6000"
                }
            ]
        }, {
            "attributeList": [{
                    "name": "Group",
                    "value": "1"
                }, {
                    "name": "RMedia",
                    "value": "1"
                }
            ]
        }, {
            "attributeList": [{
                    "name": "Launch",
                    "value": ""
                }, {
                    "name": "Media",
                    "value": "node6001"
                }
            ]
        }
    ]
}]

2 Answers 2

7

jq solution:

jq '.[] | select([.session[].attributeList[] 
                   | .name == "Media" and (.value | contains("node7000"))
                 ] | any ).name' jsonfile
  • .[] - iterating over all elements(objects) of the input array
  • select(<condition>) - the function produces its input unchanged if <condition> returns true for that input, and produces no output otherwise
  • contains(element) - the filter produces true if element is completely contained within the input
  • any - the filter takes as input an array of boolean values and produces true as output if any of the elements of the array are true

The output:

"Station 17200"
0
1

This is just to show how to rewrite the jq expression that RomanPerekhrest came up with so that the any(generator; condition) form of the any function is used:

.[] |
select(
        any(
                .session[].attributeList[];
                .name == "Media" and (.value | contains("node7000"))
        )
).name

This instructs the any function to extract all .session[].attributeList[] values from each element of the top-level array. It will then create an array of booleans from these attributeList elements using the given conditional expression on each of them. If any of the boolean values are true, then that element of the top-level array is selected. The name key's value is then extracted and printed.

Obviously, if you want to make the query string node7000 depend on e.g. a shell variable, then you'll use --arg to pass that into the expression:

query_string=node7000
jq --arg media "$query_string" '.[] | select(any(.session[].attributeList[]; .name == "Media" and (.value | contains($media)))).name' file.json

Change contains($media) into test($media) if you want to pass a PCRE regular expression rather than a string. This would additionally allow us to specifically look for e.g. node7000 using word-boundary symbols (\b), to avoid risking false positive substring matches with strings like node70001:

jq --arg media '\bnode7000\b' '.[] | select(any(.session[].attributeList[]; .name == "Media" and (.value | test($media)))).name' file.json

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .