简体   繁体   中英

Using jq to search for a value based on a key located deep in json file

I am new to jq and I'm trying to use it to search for a value in a json file based on a key that is located deep in the json structure. Here is a sample of my json file:

{
  "data": {
    "inventory": {
      "location": "remote",
      "list": {
        "content": [
          {
            "item": {
              "name": "minivan"
            },
            "owner": {
              "id": "12345",
              "state": "CA"
            }
          },
          {
            "item": {
              "name": "sedan"
            },
            "owner": {
              "id": "67890",
              "state": "AZ"
            }
          }
        ]
      }
    }
  }
}

An example of search that I'm trying to do is:

select item.name where owner.id = "67890"

and the expected output would be:

item.name = "sedan"

I'm trying to run the following:

jq '.[] | select .owner.id = "67890" | .item.name' json

and it generates an error:

jq: error: select/0 is not defined at <top-level>, line 1:
.[] | select .owner.id = "67890" | .item.name      
jq: 1 compile error

Any pointers on how to do this in jq would be much appreciated! Thanks!

First, you have to "navigate" to where you want to make the query. This seems to be an array.

.data.inventory.list.content
[
  {
    "item": {
      "name": "minivan"
    },
    "owner": {
      "id": "12345",
      "state": "CA"
    }
  },
  {
    "item": {
      "name": "sedan"
    },
    "owner": {
      "id": "67890",
      "state": "AZ"
    }
  }
]

Demo

Next, let's iterate over that array's items, which gives us a stream of objects.

.[]
{
  "item": {
    "name": "minivan"
  },
  "owner": {
    "id": "12345",
    "state": "CA"
  }
}
{
  "item": {
    "name": "sedan"
  },
  "owner": {
    "id": "67890",
    "state": "AZ"
  }
}

Demo

From these objects we select those that match your criteria.

select(.owner.id == "67890")
{
  "item": {
    "name": "sedan"
  },
  "owner": {
    "id": "67890",
    "state": "AZ"
  }
}

Demo

Finally, we extract the value you're interested in.

.item.name
"sedan"

Demo

Everything combined in a jq call would be:

jq '.data.inventory.list.content[] | select(.owner.id == "67890").item.name'
"sedan"

Demo

This output is still valid JSON document (containing nothing but a JSON string). If you want to process the output as raw text, use the --raw-output (or -r ) option:

jq -r '.data.inventory.list.content[] | select(.owner.id == "67890").item.name'
sedan

Demo

Here's a solution that avoids having to "navigate" to the right place, and which is also quite close to your SQL-like query:

..
| objects 
| select(.owner and 
         (.owner|type=="object" and .id == "67890"))
  .item.name

or more succinctly:

..|objects|select(.owner.id? == "67890").item.name

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM