Deleting multiple keys at once with jq

Viewed 40153

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?

6 Answers

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
  • doesn't require quotation marks (which you may feel makes it more readable)
  • doesn't group the paths (requires you to retype .[] 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
  • Combines subpaths under the "last-common ancestor" (which in this case is the top-level list iterator .[])

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
  • Requires both quotation marks and array of singleton arrays
  • Requires you to put it back into a list (with the start and end square brackets)

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.

A better compromise between "array-style" and "dot-style" notation mentioned in by Louis in his answer.

del(.[] | .Country, .number, .Language)

jqplay


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$"].

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

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.

Related