548

I have the following json file:

{
    "FOO": {
        "name": "Donald",
        "location": "Stockholm"
    },
    "BAR": {
        "name": "Walt",
        "location": "Stockholm"
    },
    "BAZ": {
        "name": "Jack",
        "location": "Whereever"
    }
}

I am using jq and want to get the "name" elements of the objects where 'location' is 'Stockholm'.

I know I can get all names by

cat json | jq .[] | jq ."name"
"Jack"
"Walt"
"Donald"

But I can't figure out how to print only certain objects, given the value of a sub key (here: "location" : "Stockholm").

0

6 Answers 6

779

Adapted from this post on Processing JSON with jq, you can use the select(bool) like this:

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Sign up to request clarification or add additional context in comments.

4 Comments

How would I get the parent 'FOO', 'BAR', 'BAZ'?
I'm not sure what you mean by parent (do you mean key?)... it's just jq 'keys' json. If you meant the keys after the filter, giving "FOO" "BAR", use this answer and use .key instead of [.key, .value.name].
why aren't the commas preserved between the elements?
@EssexBoy If you want it to remain an array, use jq '. | map(select(.location=="Stockholm"))' json instead.
333

To obtain a stream of just the names:

$ jq '.[] | select(.location=="Stockholm") | .name' json

produces:

"Donald"
"Walt"

To obtain a stream of corresponding (key name, "name" attribute) pairs, consider:

$ jq -c 'to_entries[]
        | select (.value.location == "Stockholm")
        | [.key, .value.name]' json

Output:

["FOO","Donald"]
["BAR","Walt"]

9 Comments

He wants the whole object based on location: "I can't figure out how to print only certain objects, given the value of a sub key"
You don't need the pipe after selection: $ jq '.[] | select(.location=="Stockholm").name' json
Making the name key variable (use a shell function with $1 as parameter) does not work: termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. I call it like cool_fn Name1. However, this works: termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Here is the solution if you like it variable.
@Fo - In the body of the question, the OP was quite specific: 'I want to get the "name" elements of the objects'. Evidently, in the title of the Q, the OP was using the word "objects" in a generic sense.
|
66

I had a similar related question: What if you wanted the original object format back (with key names, e.g. FOO, BAR)?

Jq provides to_entries and from_entries to convert between objects and key-value pair arrays. That along with map around the select

These functions convert between an object and an array of key-value pairs. If to_entries is passed an object, then for each k: v entry in the input, the output array includes {"key": k, "value": v}.

from_entries does the opposite conversion, and with_entries(foo) is a shorthand for to_entries | map(foo) | from_entries, useful for doing some operation to all keys and values of an object. from_entries accepts key, Key, name, Name, value and Value as keys.

jq15 < json 'to_entries | map(select(.value.location=="Stockholm")) | from_entries'

{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

Using the with_entries shorthand, this becomes:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

1 Comment

One thing that keeps biting me is that you need to remember that when using with_entries(), you usually want to also use .value in the select clause. This is because the to_entries macro converts the given entries to .key and .value pair, which also happens with with_entries.
44

Just try this one as a full copy paste in the shell and you will grasp it.

# pass the multiline string to the jq, use the jq to 
# select the attribute named "card_id" 
# ONLY if its neighbour attribute
# named "card_id_type" has the "card_id_type-01" value.
# jq -r means give me ONLY the value of the jq query no quotes aka raw


cat << EOF | \
    jq -r '.[]| select (.card_id_type == "card_id_type-01")|.card_id'
    [  
     { "card_id": "id-00", "card_id_type": "card_id_type-00"},
     { "card_id": "id-01", "card_id_type": "card_id_type-01"},
     { "card_id": "id-02", "card_id_type": "card_id_type-02"}
    ]
EOF
# this ^^^ MUST start first on the line - no whitespace there !!!
# outputs:
# id-01

or with an aws cli command

 # list my vpcs or
 # list the values of the tags which names are "Name" 
 aws ec2 describe-vpcs | jq -r '.| .Vpcs[].Tags[]
        |select (.Key == "Name") | .Value'|sort  -nr

Note that you could move up and down in the hierarchy both during the filtering phase and during the selecting phase :

 kubectl get services --all-namespaces -o json | jq -r '
 .items[] | select( .metadata.name 
     | contains("my-srch-string")) | 
     { name: .metadata.name, ns: .metadata.namespace 
     , nodePort: .spec.ports[].nodePort
     , port: .spec.ports[].port}
 '

2 Comments

I dont understand why this least voted, and not accepted, comment is at the top?
check your personal settings for sorting the answers ... it might be based on last modified ts ;o)
3

Hopefully this helps others, ive used jq in 100s of my own scripts, but i fight with using vars in it every single time... in this case below was only way i could get a number var to pass to it (ie single quotes around the arg/var):

id=26533

cat mydata.json | jq -r --arg id "$id" '.sensor[] |
select(.objid=='$id').probe'

Comments

0

To keep the object in the original format:

cat json | jq '. | del(.[] | select(.location!="Stockholm"))'

Output:

{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.