43

I have the following JSON input:

{
  "zk_kafka": [
    {
      "InstanceType": "t2.medium",
      "zkMemory": "16",
      "kafkaMemory": "8"
    },
    {
      "InstanceType": "t2.small",
      "zkMemory": "8",
      "kafkaMemory": "4"
    }
  ],
  "es_hdfs": [
    {
      "InstanceType": "t2.medium",
      "esMemory": "16",
      "hdfsMemory": "8"
    },
    {
      "InstanceType": "t2.small",
      "esMemory": "8",
      "hdfsMemory": "4"
    }
  ]
}

First I want to select an array by a property name. And then I want to select an object of the array by the value of the property InstanceType.

Example for the property zk_kafka and the value t2.medium:

{
  "InstanceType": "t2.medium",
  "zkMemory": "16",
  "kafkaMemory": "8"
}

I know how to select the array:

jq .zk_kafka

But I do not know how to filter the array of object by a property value.

ceving
  • 21,900
  • 13
  • 104
  • 178
Rehan Ch
  • 805
  • 3
  • 13
  • 18

2 Answers2

68

Use the select filter of jq:

jq '.zk_kafka | .[] | select(.InstanceType == "t2.medium")'

Use the --arg option to pass an argument to the query to avoid injections.

jq --arg instance "t2.medium" '.zk_kafka | .[] | select(.InstanceType == $instance)'

jq has a manual, a tutorial and a cookbook.

ceving
  • 21,900
  • 13
  • 104
  • 178
  • The quoting works fine. But keep in mind that you have to escape the regular expression according to the requirements of `sed`. – ceving Sep 06 '17 at 08:45
  • { "InstanceType": "t2.medium", "zkMemory": "16", "kafkaMemory": "8" }, { "InstanceType": "t2.small", "zkMemory": "8", "kafkaMemory": "4" } this is my block.If matches t2.medium then it should give me entire block and t2.medium will come from variable.In pattern I gave manually t2.medium and it worked but not accepting from variable. – Rehan Ch Sep 06 '17 at 08:48
  • Why do you want to use `sed`, if you have already `jq`? Forget `sed`. `jq` is all you need. Edit your question. Show complete input and complete command and expected output. – ceving Sep 06 '17 at 09:24
  • { "zk_kafka": [ { "InstanceType": "t2.medium", "zkMemory": "16", "kafkaMemory": "8" }, { "InstanceType": "t2.small", "zkMemory": "8", "kafkaMemory": "4" } ], "es_hdfs": [ { "InstanceType": "t2.medium", "esMemory": "16", "hdfsMemory": "8" }, { "InstanceType": "t2.small", "esMemory": "8", "hdfsMemory": "4" } ] } I want a block from zk_kafka when matches t2.medium. – Rehan Ch Sep 06 '17 at 09:53
  • expected output is { "InstanceType": "t2.medium", "zkMemory": "16", "kafkaMemory": "8" }, – Rehan Ch Sep 06 '17 at 09:54
  • Thanks, its working.I tried some alternatives but this is the best solution – Rehan Ch Sep 06 '17 at 12:18
  • Technically unrelated but since this is a question people new to `jq` like me will come across: If your filter returns multiple items `jq` will just output them after another. To get an actual list back, you apparently just enclose your command in `[ ]`: `jq '[ .zk_kafka | .[] | select(.InstanceType == "t2.medium") ]'` – Atemu Mar 23 '21 at 15:00
  • What if I want to update the value of any property in the returned node, in fact, updating the original JSON string after filtering? – shzyincu Oct 22 '21 at 21:21
  • @shzyincu You need to use the update assignment operator [|=](https://stedolan.github.io/jq/manual/#Assignment). – ceving Oct 23 '21 at 08:35
  • @ceving if i have an array and I have to update and nested property on a condition of its parent sibling node? – shzyincu Oct 23 '21 at 19:48
  • @shzyincu Maybe you should write a question instead of a comment. – ceving Oct 25 '21 at 06:34
0

Alternatively, you can also use map():

jq '.zk_kafka | map(select(.InstanceType == "t2.medium"))' input.json
zabop
  • 6,750
  • 3
  • 39
  • 84