Search code examples
jsonjqdelete-operator

Delete a JSON object when a value inside the object matches a designated value (jq)


The goal is to delete an entire object in a JSON file that contain a key/value pair specified in a JQ script.

For example, all objects with /unwanted-path/ in path would be removed:

input.json:

[
    {
        "path": "/path-1/",
        "guide": "Guide 1"
    },
    {
        "path": "/path-2/",
        "guide": "Guide 2"
    },
    {
        "path": "/unwanted-path/",
        "guide": "Guide 3"
    }
]

output.json:

[
    {
        "path": "/path-1/",
        "guide": "Guide 1"
    },
    {
        "path": "/path-2/",
        "guide": "Guide 2"
    }
]

This JQ script is the closest I have come to in terms of a potential successful approach, but of course its intent is different and does not accomplish the goal.

jq '.[] | walk(if type == "object" then del(.path) else . end)' original.json > modified.json

Is there a way to add logic there that designates a key to go with path?

The key will always be path, but there are several path values I will filter against. If there is a way to filter against more than one path value a time, that is ideal, but not critical.


Solution

  • The following code shows how to solve your task with four examples

    #!/bin/bash
    
    FILE='
    [
        {
            "path": "/path-1/",
            "guide": "Guide 1"
        },
        {
            "path": "/unwanted-path-2/",
            "guide": "Guide 2"
        },
        {
            "path": "/path-3/",
            "guide": "Guide 3",
            "sub": [
                {
                    "path": "/unwanted-path-4/",
                    "guide": "Guide 4"
                },
                {
                    "path": "/path-5/",
                    "guide": "Guide 5"
                },
                [
                    {
                        "path": "/path-6/",
                        "guide": "Guide 6"
                    },
                    {
                        "path": "/unwanted-path-7/",
                        "guide": "Guide 7"
                    }
                ]
            ]
        }
    ]
    '
    
    UNWANTED='/unwanted-path-2/'
    echo "example 1: keep only objects in array that does not have the unwanted path '$UNWANTED' (narrow search)"
    jq --arg unwantedPath "$UNWANTED" \
       'map(select(.path != $unwantedPath))' <<< "$FILE"
    
    UNWANTED='/unwanted-path-7/'
    echo -e "\nexample 2: delete objects that have the unwanted path '$UNWANTED' exactly (deep search)"
    jq --arg unwantedPath "$UNWANTED" \
       'del(..| objects | select(.path == $unwantedPath)) ' <<< "$FILE"
    
    UNWANTED='unwanted'
    echo -e "\nexample 3: delete objects that have the unwanted path '$UNWANTED' partially (deep search)"
    jq --arg unwantedPath "$UNWANTED" \
       'del(..| objects | select(.path | index($unwantedPath) != null)) ' <<< "$FILE"
    
    UNWANTED='["/unwanted-path-4/", "/unwanted-path-7/"]'
    echo -e "\nexample 4: delete objects that have one of unwanted paths '$UNWANTED' (deep search)"
    jq --argjson unwantedPath "$UNWANTED" \
       'del(..| objects | select(.path | IN($unwantedPath[]))) ' <<< "$FILE"
    

    output example 1: keep only objects in array that does not have the unwanted path '/unwanted-path-2/' (narrow search)

    [
      {
        "path": "/path-1/",
        "guide": "Guide 1"
      },
      {
        "path": "/path-3/",
        "guide": "Guide 3",
        "sub": [
          {
            "path": "/unwanted-path-4/",
            "guide": "Guide 4"
          },
          {
            "path": "/path-5/",
            "guide": "Guide 5"
          },
          [
            {
              "path": "/path-6/",
              "guide": "Guide 6"
            },
            {
              "path": "/unwanted-path-7/",
              "guide": "Guide 7"
            }
          ]
        ]
      }
    ]
    

    output example 2: delete objects that have the unwanted path '/unwanted-path-7/' exactly (deep search)

    [
      {
        "path": "/path-1/",
        "guide": "Guide 1"
      },
      {
        "path": "/unwanted-path-2/",
        "guide": "Guide 2"
      },
      {
        "path": "/path-3/",
        "guide": "Guide 3",
        "sub": [
          {
            "path": "/unwanted-path-4/",
            "guide": "Guide 4"
          },
          {
            "path": "/path-5/",
            "guide": "Guide 5"
          },
          [
            {
              "path": "/path-6/",
              "guide": "Guide 6"
            }
          ]
        ]
      }
    ]
    

    output example 3: delete objects that have the unwanted path 'unwanted' partially (deep search)

    [
      {
        "path": "/path-1/",
        "guide": "Guide 1"
      },
      {
        "path": "/path-3/",
        "guide": "Guide 3",
        "sub": [
          {
            "path": "/path-5/",
            "guide": "Guide 5"
          },
          [
            {
              "path": "/path-6/",
              "guide": "Guide 6"
            }
          ]
        ]
      }
    ]
    

    output example 4: delete objects that have one of unwanted paths '["/unwanted-path-4/", "/unwanted-path-7/"]' (deep search)

    [
      {
        "path": "/path-1/",
        "guide": "Guide 1"
      },
      {
        "path": "/unwanted-path-2/",
        "guide": "Guide 2"
      },
      {
        "path": "/path-3/",
        "guide": "Guide 3",
        "sub": [
          {
            "path": "/path-5/",
            "guide": "Guide 5"
          },
          [
            {
              "path": "/path-6/",
              "guide": "Guide 6"
            }
          ]
        ]
      }
    ]