skip to Main Content

I have the following JSON:

{
    "query": "rest ec",
    "elected_facts_mapping": {
        "AWS": {
            "ECS": {
                "attachments": [
                    "restart_ecs"
                ],
                "text": [
                    "Great!"
                ]
            }
        }
    },
    "top_facts_mapping": {
        "AWS": {
            "ECS": {
                "attachments": [
                    "restart_ecs"
                ],
                "text": [
                    "Great!"
                ]
            },
            "EC2": {
                "attachments": [
                    "create_ec2"
                ],
                "text": [
                    "Awesome"
                ]
            }
        },
        "GitHub": {
            "Pull": {
                "attachments": [
                    "pull_req"
                ],
                "text": [
                    "Be right on it"
                ]
            }
        },
        "testtttt": {
            "test": {
                "attachments": [
                    "hello_world"
                ],
                "text": [
                    "Be right on it"
                ]
            }
        },
        "fgjgh": {
            "fnfgj": {
                "attachments": [
                    "hello_world"
                ],
                "text": [
                    "Be right on it"
                ]
            }
        },
        "tessttertre": {
            "gfdgfdgfd": {
                "attachments": [
                    "hello_world"
                ],
                "text": [
                    "Great!"
                ]
            }
        }
    },
    "elected_facts_with_prefix_text": null
}

And I want to access to top_facts_mapping's first key AWS and it’s first key ECS

I am trying to do this (in my DSL):

'.span | fromjson'
'.span_data.top_facts_mapping | keys[0]'
'.span_data.top_facts_mapping[${top_facts_prepare_top_fact_topic}] | keys[0]'
'.top_facts_prepare_top_fact_topic_subtopic[${top_facts_prepare_top_fact_topic}][${top_facts_prepare_top_fact_topic_subtopic}]'

3

Answers


  1. You could use the keys_unsorted builtin, since the underlying object is a dictionary and not a list

    .top_facts_mapping | keys_unsorted[0] as $k | .[$k] | .[keys_unsorted[0]]
    

    The above filter could be re-written with a simple function

    def get_firstkey_val: keys_unsorted[0] as $k | .[$k];
    
    .top_facts_mapping | 
      get_firstkey_val | get_firstkey_val
    

    Or with some jq trick-play, assumes the path provided top_facts_mapping is guaranteed to exist

    getpath([ paths | select(.[-3] == "top_facts_mapping" ) ] | first)
    

    Since the paths built-in constructs the root to leaf paths as arrays, we all paths containing the second to last field (denoted by .[-3]) as "top_facts_mapping" which returns paths inside it

    From which first selects the first entity in the list i.e. below list

    [
      "top_facts_mapping",
      "AWS",
      "ECS"
    ]
    

    Use getpath/1 to obtain the JSON value at the obtained path.

    If there is a risk of the key top_facts_mapping not being present in the JSON, getpath/1 could return an error as written above. Fix it by adding a proper check

    ([ paths | select(.[-3] == "top_facts_mapping" ) ] | first) as $p | 
    if $p | length > 0 then getpath($p) else empty end
    
    Login or Signup to reply.
  2. You could use to_entries to turn the object into an array of key-value pairs, then select the first value using [0].value

    .top_facts_mapping | to_entries[0].value | to_entries[0].value
    
    {
      "attachments": [
        "restart_ecs"
      ],
      "text": [
        "Great!"
      ]
    }
    

    Demo

    If at one level the object may be empty, you can prepend each to_entries with try (optionally followed by a catch clause)

    Login or Signup to reply.
  3. Here’s a stream-based approach which disassembles the input using the --stream option, filters for the "top_facts_mapping" key on top level .[0][0], truncates the stream to descend 3 levels, re-assembles the stream using fromstream, and outputs the first match:

    jq --stream -n 'first(fromstream(3| truncate_stream(inputs | select(.[0][0] == "top_facts_mapping"))))'
    
    {
      "attachments": [
        "restart_ecs"
      ],
      "text": [
        "Great!"
      ]
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search