Reputation:
I have the following json file which contains this array structure:
{
"outer": [
{
"inner": [
{
"value": "val1"
},
{
"value": "val3"
}
]
},
{
"inner": [
{
"value": "val2"
},
{
"value": "val1"
}
]
},
{
"inner": [
{
"value": "val2"
},
{
"value": "val1"
},
{
"value": "val3"
}
]
}
]
}
I want to delete the inner
array from the outer
array whose elements have specific values and and is of certain length. E.g., if I want to delete the inner
array which contains values "val1"
and "val2"
the result should be:
{
"outer": [
{
"inner": [
{
"value": "val1"
},
{
"value": "val3"
}
]
},
{
"inner": [
{
"value": "val2"
},
{
"value": "val1"
},
{
"value": "val3"
}
]
}
]
}
I have tried
jq 'del( .outer[]|select(.inner[0].value == "val1"))'
but I do not know how to check for the second condition, the length and on top of that the values may appear in any order.
Upvotes: 0
Views: 1198
Reputation: 116880
Here is a solution which should work on all versions of jq at least from version 1.3 onwards, and which is readily adapted to take into account additional criteria, as mentioned in the Q:
# A helper function for defining the retention criteria.
# It is assumed that the input is the array to be checked and that
# `match` is already sorted.
def retain( match ): (map(.value) | sort) != match;
.outer |= map( select( .inner | retain( ["val1", "val2"] ) ))
Upvotes: 1
Reputation: 72266
The jq
filter you are looking for is:
del(.outer[] | select(.inner | map(.value) | sort == ["val1", "val2"]))
.inner | map(.value)
produces an array that contains the values associated to the value
key from all objects contained by .inner
.
sort
is needed because ==
does a one-to-one comparison of arrays. This way it matches the objects contained in .inner
no matter their order. Of course, you have to use a sorted array on the right-hand side (i.e. ["val1", "val2"]
and not ["val2", "val1"]
).
See it in action.
Upvotes: 1