Delete objects and arrays with jq which match a ke

2020-08-25 05:48发布

问题:

I have a JSON with the following content:

{
  "data": [
    {
      "name": "Test",
      "program": {
        "publicAccess": "--------",
        "externalAccess": false,
        "userGroupAccesses": [
          {
            "access": "r-------"
          },
          {
            "access": "rw------"
          }
        ],
        "id": "MmBqeMLIC2r"
      },
      "publicAccess": "rw------"
    }
  ]
}

And I want to delete all keys (recursively) which match publicAccess or userGroupAccesses, so that my JSON looks like this:

{
  "data": [
    {
      "name": "Test",
      "program": {
        "externalAccess": false,
        "id": "MmBqeMLIC2r"
      }
    }
  ]
}

I've copied jq's builtin walk function from source.

# 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;

# My Code
walk(if (type == "object" and .publicAccess)
        then del(.publicAccess)
     elif (type == "array" and .userGroupAccesses)
        then del(.userGroupAccesses)
     else
       .
end )

Gives me jq: error (at <stdin>:2622): Cannot index array with string "userGroupAccesses". Also if I use .userGroupAccesses[] - How do I get the result?

Snippet on jqplay: https://jqplay.org/s/1m7wAeHMTu

回答1:

Your problem is when type == "array" is true . will be an array so .userGroupAccesses won't work. What you want to do is focus on the case when . is an object. In your call to walk you only need to check for type == "object" and then remove the members you don't want. e.g.

walk(if type == "object" then del(.publicAccess, .userGroupAccesses) else . end)

Try it online at jqplay.org

You can also solve this without walk by using Recursive Descent .. e.g.

del(.. | .publicAccess?, .userGroupAccesses?)

Try it online at jqplay.org



标签: arrays json jq