Search code examples
jsonselectjq

jq - how to filter values in an inner array without knowing the key


I have the following JSON:

{
  "ids": {
    "sda": [
      "scsi-0QEMU_QEMU_HARDDISK_drive-scsi2"
    ],
    "sdb": [
      "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
    ],
    "sdb1": [
      "lvm-pv-uuid-lvld3A-oA4k-hC19-DXzv-D0Fq-xyME-BwgJid",
      "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part1"
    ],
    "sdc": [
      "lvm-pv-uuid-pWes2W-dgYF-l8hG-La48-9ozH-hPdU-MOkOtf",
      "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
    ]
  }
}

What I want to achieve is to search for .*scsi0$ in the values of the inner array and get sdb as the result.


Solution

  • Using JSON jq endswith to filter results:

    .ids | to_entries[] | select(.value[] | endswith("scsi0")) | .key
    

    Results in:

    "sdb"
    

    Try it here: https://jqplay.org/s/DAhKosXXgiA


    Let's break it down...

    First get .ids, which returns:

    {
      "sda": [
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi2"
      ],
      "sdb": [
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
      ],
      "sdb1": [
        "lvm-pv-uuid-lvld3A-oA4k-hC19-DXzv-D0Fq-xyME-BwgJid",
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part1"
      ],
      "sdc": [
        "lvm-pv-uuid-pWes2W-dgYF-l8hG-La48-9ozH-hPdU-MOkOtf",
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
      ]
    }
    

    ...then pipe the results to the to_entries function to convert that to an array of {key, value} objects.

    .ids | to_entries returns:

    [
      {
        "key": "sda",
        "value": [
          "scsi-0QEMU_QEMU_HARDDISK_drive-scsi2"
        ]
      },
      {
        "key": "sdb",
        "value": [
          "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
        ]
      },
      {
        "key": "sdb1",
        "value": [
          "lvm-pv-uuid-lvld3A-oA4k-hC19-DXzv-D0Fq-xyME-BwgJid",
          "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part1"
        ]
      },
      {
        "key": "sdc",
        "value": [
          "lvm-pv-uuid-pWes2W-dgYF-l8hG-La48-9ozH-hPdU-MOkOtf",
          "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
        ]
      }
    ]
    

    ...next stream the list of objects with the iterator operator .[].

    .ids | to_entries[] returns:

    {
      "key": "sda",
      "value": [
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi2"
      ]
    }
    {
      "key": "sdb",
      "value": [
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
      ]
    }
    {
      "key": "sdb1",
      "value": [
        "lvm-pv-uuid-lvld3A-oA4k-hC19-DXzv-D0Fq-xyME-BwgJid",
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part1"
      ]
    }
    {
      "key": "sdc",
      "value": [
        "lvm-pv-uuid-pWes2W-dgYF-l8hG-La48-9ozH-hPdU-MOkOtf",
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
      ]
    }
    

    ...and select from a stream of values, .ids | to_entries[] | select(.value[]) where value endswith "scsi0", select(.value[] | endswith("scsi0")) :

    {
      "key": "sdb",
      "value": [
        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
      ]
    }
    

    ...finally, get the key value.

    .ids | to_entries[] | select(.value[] | endswith("scsi0")) | .key returns:

    "sdb"
    

    Command line:

    jq '.ids | to_entries[] | select(.value[] | endswith("scsi0")) | .key'
    

    Try it here: https://jqplay.org/s/DAhKosXXgiA