Reputation: 2297
I need to delete multiple keys at once from some JSON (using jq
), and I'm trying to learn if there is a better way of doing this, than calling map and del every time. Here's my input data:
test.json
[
{
"label": "US : USA : English",
"Country": "USA",
"region": "US",
"Language": "English",
"locale": "en",
"currency": "USD",
"number": "USD"
},
{
"label": "AU : Australia : English",
"Country": "Australia",
"region": "AU",
"Language": "English",
"locale": "en",
"currency": "AUD",
"number": "AUD"
},
{
"label": "CA : Canada : English",
"Country": "Canada",
"region": "CA",
"Language": "English",
"locale": "en",
"currency": "CAD",
"number": "CAD"
}
]
For each item, I want to remove the number, Language, and Country keys. I can do that with this command:
$ cat test.json | jq 'map(del(.Country)) | map(del(.number)) | map(del(.Language))'
That works fine, and I get the desired output:
[
{
"label": "US : USA : English",
"region": "US",
"locale": "en",
"currency": "USD"
},
{
"label": "AU : Australia : English",
"region": "AU",
"locale": "en",
"currency": "AUD"
},
{
"label": "CA : Canada : English",
"region": "CA",
"locale": "en",
"currency": "CAD"
}
]
However, I'm trying to understand if there is a jq
way of specifying multiple labels to delete, so I don't have to have multiple map(del())
directives?
Upvotes: 71
Views: 69750
Reputation: 133
In addition to @user3899165's answer, I found that to delete a list of keys from "sub-object"
example.json
{
"a": {
"b": "hello",
"c": "world",
"d": "here's",
"e": "the"
},
"f": {
"g": "song",
"h": "that",
"i": "I'm",
"j": "singing"
}
}
$ jq 'del(.a["d", "e"])' example.json
Upvotes: 7
Reputation: 321
This question is very high in the google results, so I'd like to note that some time in the intervening years, del
has apparently been altered so that you can delete multiple keys with just:
del(.key1, .key2, ...)
So don't tear your hair out trying to figure out the syntax work-arounds, assuming your version of jq is reasonably current.
Upvotes: 22
Reputation: 3294
A better compromise between "array-style" and "dot-style" notation mentioned in by Louis in his answer.
del(.[] | .Country, .number, .Language)
This form can also be used to delete a list of keys from a nested object (see russholio's answer):
del(.a | .d, .e)
Implying that you can also pick a single index to delete keys from:
del(.[1] | .Country, .number, .Language)
Or multiple:
del(.[2,3,4] | .Country,.number,.Language)
You can delete a range using the range()
function (slice notation doesn't work):
del(.[range(2;5)] | .Country,.number,.Language) # same as targetting indices 2,3,4
Some side notes:
map(del(.Country,.number,.Language))
# Is by definition equivalent to
[.[] | del(.Country,.number,.Language)]
If the key contains special characters or starts with a digit, you need to surround it with double quotes like this:
."foo$"
, or else.["foo$"]
.
Upvotes: 16
Reputation: 5576
There is no need to use both map
and del
.
You can pass multiple paths to del
, separated by commas.
Here is a solution using "dot-style" path notation:
jq 'del( .[] .Country, .[] .number, .[] .Language )' test.json
.[]
once per path)Here is an example using "array-style" path notation, which allows you to combine paths with a common prefix like so:
jq 'del( .[] ["Country", "number", "Language"] )' test.json
.[]
)peak's answer uses map
and delpaths
, though it seems you can also use delpaths
on its own:
jq '[.[] | delpaths( [["Country"], ["number"], ["Language"]] )]' test.json
Overall, here I'd go for the array-style notation for brevity, but it's always good to know multiple ways to do the same thing.
Upvotes: 34
Reputation: 116880
delpaths
is also worth knowing about, and is perhaps a little less mysterious:
map( delpaths( [["Country"], ["number"], ["Language"]] ))
Since the argument to delpaths
is simply JSON, this approach is particularly useful for programmatic deletions, e.g. if the key names are available as JSON strings.
Upvotes: 6
Reputation:
You can provide a stream of paths to delete:
$ cat test.json | jq 'map(del(.Country, .number, .Language))'
Also, consider that, instead of blacklisting specific keys, you might prefer to whitelist the ones you do want:
$ cat test.json | jq 'map({label, region, locale, currency})'
Upvotes: 92