Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove all null values

Tags:

json

bash

null

jq

I am trying to remove null values from a json object using jq. I found this issue on their github and so now I'm trying to remove them with del. I have this:

'{ id: $customerId, name, phones: ([{ original: .phone }, 
 { original: .otherPhone}]), email} | del(. | nulls)'

This doesn't seem to do anything. However if I replace nulls with .phones it does remove the phone numbers.

like image 935
Ela Avatar asked Sep 14 '16 22:09

Ela


People also ask

How do you eliminate nulls in SQL?

If you want the COUNT function to count all rows of a given column, including the null values, use the ISNULL function. The ISNULL function can replace the null value with a valid value. or other SET operation. (1) - NULL values are eliminated.

How do you remove all nulls in tableau?

To filter null dimensions or discrete measures, drag the pill to the Filter shelf and deselect Null. The null value will appear in the list with discrete values, where you can then remove it.


4 Answers

The following illustrates how to remove all the null-valued keys from a JSON object:

jq -n '{"a":1, "b": null, "c": null} | with_entries( select( .value != null ) )'
{
  "a": 1
}

Alternatively, paths/0 can be used as follows:

. as $o | [paths[] | {(.) : ($o[.])} ] | add

By the way, del/1 can also be used to achieve the same result, e.g. using this filter:

reduce keys[] as $k (.; if .[$k] == null then del(.[$k]) else . end)

Or less obviously, but more succinctly:

del( .[ (keys - [paths[]])[] ] )

And for the record, here are two ways to use delpaths/1:

jq -n '{"a":1, "b": null, "c": null, "d":2} as $o
  | $o
  | delpaths( [  keys[] | select( $o[.] == null ) ] | map( [.]) )'


$ jq -n '{"a":1, "b": null, "c": null, "d":2}
  | [delpaths((keys - paths) | map([.])) ] | add'

In both these last two cases, the output is the same: { "a": 1, "d": 2 }

like image 58
peak Avatar answered Oct 28 '22 13:10

peak


This answer by Michael Homer on https://unix.stackexchange.com has a super concinse solution which works since jq 1.6:

del(..|nulls)

It deletes all null-valued properties (and values) from your JSON. Simple and sweet :)

nulls is a builtin filter and can be replaced by custom selects:

del(..|select(. == "value to delete"))

To remove elements based on multiple conditions, e.g. remove all bools and all numbers:

del(..|booleans,numbers)

or, to only delete nodes not matching a condition:

del(..|select(. == "value to keep" | not))

(The last example is only illustrative – of course you could swap == for !=, but sometimes this is not possible. e.g. to keep all truthy values: del(..|select(.|not)))

like image 40
knittl Avatar answered Oct 28 '22 11:10

knittl


All the other answers to date here are workarounds for old versions of jq, and it isn't clear how do do this simply in the latest released version. In JQ 1.6 or newer this will do the job to remove nulls recursively:

$ jq 'walk( if type == "object" then with_entries(select(.value != null)) else . end)' input.json

Sourced from this comment on the issue where adding the walk() function was discussed upstream.

like image 38
Caleb Avatar answered Oct 28 '22 12:10

Caleb


[WARNING: the definition of walk/1 given in this response is problematic, not least for the reason given in the first comment; note also that jq 1.6 defines walk/1 differently.]

I am adding the new answer to emphasize the extended version of the script by @jeff-mercado. My version of the script assumes the empty values are as follows:

  • null;
  • [] - empty arrays;
  • {} - empty objects.

Removing of empty arrays and objects was borrowed from here https://stackoverflow.com/a/26196653/3627676.

def walk(f):
    . as $in | 
    if type == "object" then
        reduce keys[] as $key
            ( {}; . + { ($key): ( $in[$key] | walk(f) ) } ) | f
    elif type == "array" then 
        select(length > 0) | map( walk(f) ) | f
    else 
        f
    end;

walk(
    if type == "object" then
        with_entries(select( .value != null and .value != {} and .value != [] ))
    elif type == "array" then
        map(select( . != null and . != {} and .!= [] ))
    else
        .
    end
)
like image 43
jsxt Avatar answered Oct 28 '22 13:10

jsxt