Search code examples
jsonselectkeyjqjsonlines

jq filter for object with target value or key is not exist


I have jsonlines data which and would like to find 1. value is empty object or 2. key is not exist . In the following sample, I wonder take the result of items which .items.spec.resource={} or .items.spec.limits|requests which key not exist.

data='{"items":[{"metadata":{"name":"pod01"},"spec":{"containers":[{"name":"con01_01","resources":{"limits":{"cpu":"100m"},"requests":{"cpu":"100m"}}},{"name":"con01_02","resources":{"limits":{"cpu":"100m"},"requests":{"cpu":"100m"}}}]}},{"metadata":{"name":"pod02"},"spec":{"containers":[{"name":"con02_01","resources":{"limits":{"cpu":"100m"},"requests":{"cpu":"100m"}}},{"name":"con02_02","resources":{"limits":{"cpu":"100m"}}}]}},{"metadata":{"name":"pod03"},"spec":{"containers":[{"name":"con03_01","resources":{"limits":{"cpu":"100m"},"requests":{"cpu":"100m"}}},{"name":"con03_02","resources":{}}]}}]}'
list=$(echo $data | jq '.items[] | select(.spec.containers[].resources.requests == null or  .spec.containers[].resources.limits == null or .spec.containers[].resources == {})')
echo $list 

Here comes the result

{ 
  "metadata": { "name": "pod02" }, 
  "spec": { 
    "containers": [ 
      { "name": "con02_01", 
        "resources": { 
                       "limits": { "cpu": "100m" }, 
                       "requests": { "cpu": "100m" } 
                     } 
      }, 
      { "name": "con02_02", 
        "resources": { 
                       "limits": { "cpu": "100m" } 
                     } 
      } 
    ] 
  } 
} 
{ 
  "metadata": { "name": "pod03" },
  "spec": {
    "containers": [ 
      { 
        "name": "con03_01", 
        "resources": { 
                       "limits": { "cpu": "100m" }, 
                       "requests": { "cpu": "100m" } 
                     } 
      }, 
      { "name": "con03_02", 
        "resources": {} 
      } 
    ] 
  } 
} 

{ 
  "metadata": { "name": "pod03" }, 
  "spec": { 
    "containers": [ 
      { "name": "con03_01", 
        "resources": { 
                        "limits": { "cpu": "100m" }, 
                        "requests": { "cpu": "100m" } 
                     } 
      }, 
      { "name": "con03_02", 
        "resources": {} 
      } 
    ] 
  } 
} 
  
{ 
  "metadata": { "name": "pod03" }, 
  "spec": { 
    "containers": [ 
      { "name": "con03_01", 
        "resources": { 
                        "limits": { "cpu": "100m" }, 
                        "requests": { "cpu": "100m" } 
                      } 
      }, 
      { "name": "con03_02", 
        "resources": {} 
      } 
    ] 
  } 
}

I don't understand the repeat part, I guess it is because of the conditions, how can I get the part of above conditions, I would like to filter the part of metadata and spec.containers which meet conditions.


Solution

  • In accordance with your explanatory comment, it would appear you could achieve what you want using jq "$-variables":

    jq -c '
    .items[]
    | .metadata.name as $podname
    | .spec.containers[] 
    | select(.resources.requests == null or 
             .resources.limits == null or 
             .resources == {})
    | [$podname, .name]
    '
    

    With your data, the output produced by the above would be:

    ["pod02","con02_02"]
    ["pod03","con03_02"]
    

    Simplification

    The test for the third condition (.resources == {}) is actually redundant, so the above jq filter is equivalent to:

    .items[]
    | .metadata.name as $podname
    | .spec.containers[] 
    | select(.resources | (.requests == null or .limits == null ))
    | [$podname, .name]
    
    

    Existence of a key

    To check for the existence of a key, it is generally appropriate to use has/1 since {} | .key evaluates to null. Thus you might wish to replace the select() above with:

    select( any(.resources | has("requests", "limits"); not) )