JQ JSON – How to Keep One Specific Key from Nested Object

jqjson

I have the following config.json file:

{
        "auths": {
                "reg1.io": {
                        "auth": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                },
                "reg2.io": {
                        "auth": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
                },
                "reg3.io": {
                        "auth": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
                }
        }
}

I want to keep only the reg2.io object to get:

{
        "auths": {
                "reg2.io": {
                        "auth": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
                }
        }
}

I can delete one specific object with e.g.:

→ jq 'del(.. | ."reg2.io"? )' ./config.json
{
  "auths": {
    "reg1.io": {
      "auth": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    },
    "reg3.io": {
      "auth": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
    }
  }
}

but what if i want to keep one specific object? Thanks.

Best Answer

Using select() with with_entries() to select only the key that you want:

$ jq '.auths |= with_entries(select(.key == "reg2.io"))' file
{
  "auths": {
    "reg2.io": {
      "auth": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    }
  }
}

Parametrised so that it takes the wanted key from the command line:

$ jq --arg key "reg2.io" '.auths |= with_entries(select(.key == $key))' file
{
  "auths": {
    "reg2.io": {
      "auth": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    }
  }
}

Change the == to != to delete the named key.

Note that your own attempt does not distinguish where the key is found in the document, which could cause some confusion in the general case.


Just to add a bit more explanation as to what's happening in the jq expression.

Within the with_entries() command, what's visible is the following set of objects, each with a key and a value key:

{
   "key": "reg1.io",
   "value": { "auth": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
}
{
   "key": "reg2.io",
   "value": { "auth": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" }
}
{
   "key": "reg3.io",
   "value": { "auth": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" }
}

The select() call extracts each object for which the given test is true, and discards the rest. Our test is simply "Is the value of the key key the string reg2.io?".

A call to with_entries(expr) is equivalent to to_entries | map(expr) | from_entries.

Related Question