Table of Content

Catch undefined keys and exit with 1

{
    "action": "do_something",
    "condition1": "42",
    "condition2": true
}
$ jq -n -c 'input | if .condition3 then .condition3 else null | halt_error(1) end' <<<"${my_json_variable}"

The above will result in no output and a returncode of 1 while the following will return the vaule and with exit code 0:

$ jq -n -c 'input | if .condition1 then .condition1 else null | halt_error(1) end' <<<"${my_json_variable}"
42

Outputs without quotes

$ cat output1| jq -r -c '[.[] | .certname,.report_timestamp]'
{host1,2019-10-14T11:26:32.459Z,host2,2019-10-14T11:18:29.598Z}

Outputs full result into one line

$ cat output1| jq -c '[.[] | .certname,.report_timestamp]'
{"host1","2019-10-14T11:26:32.459Z","host2","2019-10-14T11:18:29.598Z"}

Outputs full each result

$ cat output1| jq -c '.[] | {certname:.certname,report_timestamp:.report_timestamp}'
{"certname":"host1","report_timestamp":"2019-10-14T11:26:32.459Z"}
{"certname":"host2","report_timestamp":"2019-10-14T11:18:29.598Z"}

Outputs each result into one line with given vaules

$ cat output1| jq -c '.[] | [.report_timestamp,.certname]'
{"2019-10-14T11:26:32.459Z","host1"}
{"2019-10-14T11:18:29.598Z","host2"}

Sorting by values

$ cat output1| jq -c 'sort_by(.catalog_timestamp,.report_timestamp) | .[] | [.catalog_timestamp,.report_timestamp,.certname]'
{"2019-10-14T11:18:29.598Z","2019-10-14T11:18:29.598Z","host2"}
{"2019-10-14T11:26:32.459Z","2019-10-14T11:26:34.464Z","host1"}

Filter by values

$ cat output1| jq '. | select ( .certname == "host1" )'
{
    "certname":  "host1",
    "report_timestamp": "2019-10-14T11:26:32.459Z"
}
$ cat output1| jq '. | select ( .certname == "host1" ) | .report_timestamp'

"2019-10-14T11:26:32.459Z"

Filter at any values

$ cat output1| jq '. | select ( any(. == "host1") )'
{
    "certname":  "host1",
    "report_timestamp": "2019-10-14T11:26:32.459Z"
}

Filter at any values and contains

$ cat output1| jq '. | select ( any(conatins("ho")) )'
{
    "certname":  "host1",
    "report_timestamp": "2019-10-14T11:26:32.459Z"
},
{
    "certname":  "host2",
    "report_timestamp": "2019-10-14T11:18:29.598Z"
}

Filter at key names using has

$ cat output1 | jq '. | select( has("certname") )

This will return the full hash where it found a key named certname

{
    "certname":  "host1",
    "report_timestamp": "2019-10-14T11:26:32.459Z"
    ...
},
{
    "certname":  "host2",
    "report_timestamp": "2019-10-14T11:18:29.598Z"
    ...
}

Filter at keys contain match

$ cat output1 | jq '. | with_entries( select ( .key|contains("name") ))'
{
  "certname": "host1"
},
{
  "certname": "host2"
}

Filter and remove nested hashes

I had a json output where I needed to find all hosts which have external mountpoints attached + where they got mounted.

To remove the data from a nested hash, without knowing the keys of the hash, you can use something like this:

Json sample:

[{
   "hostname": "my_host1",
   "value": {
       "/": {
           "filesystem": "xfs",
           "size": "10GB",
           "user": "root",
           "group": "root"
       },
       "/mnt": {
           "filesystem": "cifs",
           "size": "4TB",
           "user": "mnt_user",
           "group": "mnt_user"
       },
       "/var": {
           "filesystem": "xfs",
           "size": "8GB",
           "user": "root",
           "group": "root"
       }
   }
},
{
   "hostname": "my_host2",
   "value": {
       "/": {
           "filesystem": "xfs",
           "size": "12GB",
           "user": "root",
           "group": "root"
       },
       "/var": {
           "filesystem": "xfs",
           "size": "8GB",
           "user": "root",
           "group": "root"
       },
       "/data/shared": {
           "filesystem": "cifs",
           "d11": "200GB",
           "d12": "shared",
           "d13": "shared"
       }
   }
}]
$ cat disk_sample.json | jq -r '.[] | select(.hostname | contains("my_")) | select(.. | .filesystem? | select(. == "cifs")) | walk( del( select(.. | .filesystem? | select(. != "cifs") ) ) ) | del(..|select(. == null))'

This will result into:

{
  "hostname": "my_host1",
  "value": {
    "/mnt": {
      "filesystem": "cifs",
      "size": "4TB",
      "user": "mnt_user",
      "group": "mnt_user"
    }
  }
}
{
  "hostname": "my_host2",
  "value": {
    "/data/shared": {
      "filesystem": "cifs",
      "d11": "200GB",
      "d12": "shared",
      "d13": "shared"
    }
  }
}

So what is it doing:

  1. select(.hostname | contains("my_")): ensures that I only get the hosts which contain the string my_
  2. select(.. | .filesystem? | select(. == "cifs")): It selects all objects which have a child(+childchild…) with the key filesystem and the value cifs
  3. walk( del( select(.. | .filesystem? | select(. != "cifs") ) ) ): it walks through the result, starting in the deepest level and deletes every objects data containing a key which has not the value cifs: it walks through the result, starting in the deepest level and deletes every objects data containing the key filesystem which has not the value cifs.
  4. del(..|select(. == null)): Removes all objects where the value is null

To only get now the hostnames + where the storages got mounted, you can add this:

Changed the parameter -r ot -c on the jq command

and appended in the jq query this: | walk( del( select(.. | .filesystem? | select(. == "cifs") ) ) )

$ cat test.json| jq -c '.[] | select(.hostname | contains("my_")) | select(.. | .filesystem? | select(. == "cifs")) | walk( del( select(.. | .filesystem? | select(. != "cifs") ) ) ) | del(..|select(. == null)) | walk( del( select(.. | .filesystem? | select(. == "cifs") ) ) ) | [.hostname,.value]'

which leads to this result:

{"hostname":"my_host1","value":{"/mnt":null}}
{"hostname":"my_host2","value":{"/data/shared":null}}

Use Value as Key

Sample json for this and merge sektion section

{
  "contacts": [
    {
      "id": 1,
      "name": "Mensch1",
      "type": "user"
    },
    {
      "id": 2,
      "name": "Team1",
      "type": "team"
    },
    {
      "id": 3,
      "name": "Mensch2",
      "type": "team"
    },
    {
      "id": 4,
      "name": "Mensch4",
      "type": "user"
    },
    {
      "id": 5,
      "name": "Mensch5",
      "type": "user"
    },
    {
      "id": 6,
      "name": "Team3",
      "type": "team"
    }
  ]
}

This is is where the join happens {(.name): .id}, before that we do a sort, to just get all items with type user.

$ jq -r  '.contacts | .[] | select (.type == "user") | {(.name): .id}' <./test.json

As resulte we get this:

{
  "Mensch1": 1
}
{
  "Mensch4": 4
}
{
  "Mensch5": 5
}

Merge

To merge the above shown result into one hash, you have to create out of the above result one single array [ ] and pipe it through an add

$ jq -r  '[.contacts | .[] | select (.type == "user") | {(.name): .id}] | add' <./test.json

Now you just get one single hash as a result of the add

{
  "Mensch1": 1,
  "Mensch4": 4,
  "Mensch5": 5
}

Variables

External

To use external variables which might contain special characters where which need to me masked or you just want to feed it from the outsoud, you could go this way:

$ jq '{ key: $value }' --arg value 'pas\\\\\3"21T!$!41tsword' -n
{
  "key": "pas\\\\\\\\\\3\"21T!$!41tsword"
}