basebandit
basebandit

Reputation: 97

JQ: Iterate through top level JSON object keys returning object(s) if value match

I am trying to return JSON objects from this dataset that contain a key whose value matches "builtin" string using JQ. This is the dataset I am using.

{
  "aws": {
    "defined": "public",
    "type": "ec2",
    "description": "Amazon Web Services",
    "auth-types": [
      "access-key"
    ],
    "credential-count": 2,
    "regions": {
      "us-east-1": {
        "endpoint": "https://ec2.us-east-1.amazonaws.com"
      },
      "us-east-2": {
        "endpoint": "https://ec2.us-east-2.amazonaws.com"
      },
      "us-west-1": {
        "endpoint": "https://ec2.us-west-1.amazonaws.com"
      },
      "us-west-2": {
        "endpoint": "https://ec2.us-west-2.amazonaws.com"
      },
      "ca-central-1": {
        "endpoint": "https://ec2.ca-central-1.amazonaws.com"
      },
      "eu-west-1": {
        "endpoint": "https://ec2.eu-west-1.amazonaws.com"
      },
      "eu-west-2": {
        "endpoint": "https://ec2.eu-west-2.amazonaws.com"
      },
      "eu-west-3": {
        "endpoint": "https://ec2.eu-west-3.amazonaws.com"
      },
      "eu-central-1": {
        "endpoint": "https://ec2.eu-central-1.amazonaws.com"
      },
      "eu-north-1": {
        "endpoint": "https://ec2.eu-north-1.amazonaws.com"
      },
      "eu-south-1": {
        "endpoint": "https://ec2.eu-south-1.amazonaws.com"
      },
      "af-south-1": {
        "endpoint": "https://ec2.af-south-1.amazonaws.com"
      },
      "ap-east-1": {
        "endpoint": "https://ec2.ap-east-1.amazonaws.com"
      },
      "ap-south-1": {
        "endpoint": "https://ec2.ap-south-1.amazonaws.com"
      },
      "ap-southeast-1": {
        "endpoint": "https://ec2.ap-southeast-1.amazonaws.com"
      },
      "ap-southeast-2": {
        "endpoint": "https://ec2.ap-southeast-2.amazonaws.com"
      },
      "ap-southeast-3": {
        "endpoint": "https://ec2.ap-southeast-3.amazonaws.com"
      },
      "ap-northeast-1": {
        "endpoint": "https://ec2.ap-northeast-1.amazonaws.com"
      },
      "ap-northeast-2": {
        "endpoint": "https://ec2.ap-northeast-2.amazonaws.com"
      },
      "ap-northeast-3": {
        "endpoint": "https://ec2.ap-northeast-3.amazonaws.com"
      },
      "me-south-1": {
        "endpoint": "https://ec2.me-south-1.amazonaws.com"
      },
      "sa-east-1": {
        "endpoint": "https://ec2.sa-east-1.amazonaws.com"
      }
    }
  },
  "google": {
    "defined": "public",
    "type": "gce",
    "description": "Google Cloud Platform",
    "auth-types": [
      "jsonfile",
      "oauth2"
    ],
    "credential-count": 1,
    "regions": {
      "us-east1": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-east4": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-central1": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-west1": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-west2": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-west3": {
        "endpoint": "https://www.googleapis.com"
      },
      "us-west4": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-east1": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-east2": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-northeast1": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-northeast2": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-northeast3": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-south1": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-southeast1": {
        "endpoint": "https://www.googleapis.com"
      },
      "asia-southeast2": {
        "endpoint": "https://www.googleapis.com"
      },
      "australia-southeast1": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-central2": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-north1": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-west1": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-west2": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-west3": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-west4": {
        "endpoint": "https://www.googleapis.com"
      },
      "europe-west6": {
        "endpoint": "https://www.googleapis.com"
      },
      "northamerica-northeast1": {
        "endpoint": "https://www.googleapis.com"
      },
      "southamerica-east1": {
        "endpoint": "https://www.googleapis.com"
      }
    }
  },
  "localhost": {
    "defined": "built-in",
    "type": "lxd",
    "description": "LXD Container Hypervisor",
    "auth-types": [
      "certificate"
    ],
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
  },
  "microk8s": {
    "defined": "built-in",
    "type": "k8s",
    "description": "A Kubernetes Cluster",
    "auth-types": [
      "certificate",
      "clientcertificate",
      "oauth2",
      "oauth2withcert",
      "userpass"
    ],
    "endpoint": "https://192.168.101.2:15443",
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
  }
}

Below is the query I am trying to fiddle with. The returned data is missing some of the fields from the original containing object. jq '..|objects|select(.defined? == "built-in")' clouds.json Returns:

{
  "defined": "built-in",
  "type": "lxd",
  "description": "LXD Container Hypervisor",
  "auth-types": [
    "certificate"
  ],
  "credential-count": 1,
  "regions": {
    "localhost": {}
  }
}
{
  "defined": "built-in",
  "type": "k8s",
  "description": "A Kubernetes Cluster",
  "auth-types": [
    "certificate",
    "clientcertificate",
    "oauth2",
    "oauth2withcert",
    "userpass"
  ],
  "endpoint": "https://192.168.100.2:16443",
  "credential-count": 1,
  "regions": {
    "localhost": {}
  },
}

I wanted it to also include the top level containing object parentheses as well as the top level key like so:

{  
"localhost": {
    "defined": "built-in",
    "type": "lxd",
    "description": "LXD Container Hypervisor",
    "auth-types": [
      "certificate"
    ],
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
  },
  "microk8s": {
    "defined": "built-in",
    "type": "k8s",
    "description": "A Kubernetes Cluster",
    "auth-types": [
      "certificate",
      "clientcertificate",
      "oauth2",
      "oauth2withcert",
      "userpass"
    ],
    "endpoint": "https://192.168.100.2:16443",
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
 }
}

Upvotes: 0

Views: 769

Answers (2)

pmf
pmf

Reputation: 36088

Just update |= each field of the input object .[] using your select statement:

jq '.[] |= select(.defined == "built-in")' clouds.json
{
  "localhost": {
    "defined": "built-in",
    "type": "lxd",
    "description": "LXD Container Hypervisor",
    "auth-types": [
      "certificate"
    ],
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
  },
  "microk8s": {
    "defined": "built-in",
    "type": "k8s",
    "description": "A Kubernetes Cluster",
    "auth-types": [
      "certificate",
      "clientcertificate",
      "oauth2",
      "oauth2withcert",
      "userpass"
    ],
    "endpoint": "https://192.168.101.2:15443",
    "credential-count": 1,
    "regions": {
      "localhost": {}
    }
  }
}

Demo

Note: For more readability, the .[] |= pattern is implemented by a function called map_values, so jq 'map_values(select(.defined == "built-in"))' clouds.json will have the same effect.

Upvotes: 2

Inian
Inian

Reputation: 85590

You can use the with_entries function that converts your objects into key and a value pair, which can in-turn be used for a select operation based on the condition

with_entries(select(.value.defined == "built-in"))

jqplay demo

Upvotes: 1

Related Questions