Elias51
Elias51

Reputation: 25

Passing Multiple Objects to jq for Recursive Filter Operation

I am trying to use jq 1.5 to develop a script that can take one or more user inputs that represent a key and recursively remove them from JSON input.

The JSON I am referencing is here: https://github.com/EmersonElectricCo/fsf/blob/master/docs/Test.json

My script, which seems to work pretty well, is as follows.

def post_recurse(f):
   def r:
      (f | select(. != null) | r), .;
      r;
def post_recurse:
   post_recurse(.[]?);
(post_recurse | objects) |= del(.META_BASIC_INFO)

However, I would like to replace META_BASIC_INFO with one or more user inputs. How would I go about accomplishing this? I presume with --arg from the command line, but I am unclear on how to incorporate this into my .jq script?

I've tried replacing del(.META_BASIC_INFO) with del(.$module) and invoking with cat test.json | ./jq -f fsf_key_filter.jq --arg module META_BASIC_INFO to test but this does not work.

Any guideance on this is greatly appreciated!

ANSWER:

Based on a couple of suggestions I was able to arrive to the following that works and users JQ.

Innvocation:

cat test.json | jq --argjson delete '["META_BASIC_INFO","SCAN_YARA"]' -f fsf_module_filter.jq

Code:

def post_recurse(f):
        def r:
                (f | select(. != null) | r), .;
                r;
def post_recurse:
        post_recurse(.[]?);
(post_recurse | objects) |= reduce $delete[] as $d (.; delpaths([[ $d ]]))

Upvotes: 1

Views: 1341

Answers (3)

peak
peak

Reputation: 116870

Here's a "one-line" solution using walk/1:

jq --arg d "META_BASIC_INFO" 'walk(if type == "object" then del(.[$d]) else . end)' input.json

If walk/1 is not in your jq, here is its definition:

# Apply f to composite entities recursively, and to atoms
def walk(f):
  . as $in
  | if type == "object" then
      reduce keys[] as $key
        ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
    elif type == "array" then map( walk(f) ) | f
    else f
    end;

If you want to recursively delete a bunch of key-value pairs, then here's one approach using --argjson:

rdelete.jq:

def rdelete(key):
  walk(if type == "object" then del(.[key]) else . end);

reduce $strings[] as $s (.; rdelete($s))

Invocation:

$ jq --argjson strings '["a","b"]' -f rdelete.jq input.json

Upvotes: 0

Jeff Mercado
Jeff Mercado

Reputation: 134511

It seems the name module is a keyword in 1.5 so $module will result in a syntax error. You should use a different name. There are other builtins to do recursion for you, consider using them instead of churning out your own.

$ jq '(.. | objects | select(has($a))) |= del(.[$a])' --arg a "META_BASIC_INFO" Test.json

Upvotes: 1

peak
peak

Reputation: 116870

You could also use delpaths/1. For example:

$ jq -n '{"a":1, "b": 1} | delpaths([["a"]])'
{
  "b": 1
}

That is, modifying your program so that the last line reads like this:

(post_recurse | objects) |= delpaths([[ $delete ]] )

you would invoke jq like so:

$ jq --arg delete "META_BASIC_INFO" -f delete.jq input.json

(One cannot use --arg module ... as "$module" has some kind of reserved status.)

Upvotes: 0

Related Questions