jmespath

Filter elements of an array that does contain a substring


I have this dataset

{
  "imageDetails": [
    {
      "registryId": "259611133533",
      "repositoryName": "core",
      "imageDigest": "sha256:b17e3f35ff2e0b9af437372d7777e1cc092994eb87dbddf2d73d467eb122cf51",
      "imageTags": [
        "master-202404300732"
      ],
      "imageSizeInBytes": 470904068,
      "imagePushedAt": "2024-04-30T09:34:19+02:00",
      "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "artifactMediaType": "application/vnd.docker.container.image.v1+json"
    },
    {
      "registryId": "259611133533",
      "repositoryName": "core",
      "imageDigest": "sha256:dfe2a1df2d6d8b39bdd37887979f027de29f802295e1b7536c31ac786fc0bbea",
      "imageTags": [
        "develop-202404230503"
      ],
      "imageSizeInBytes": 471216957,
      "imagePushedAt": "2024-04-23T07:07:14+02:00",
      "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "artifactMediaType": "application/vnd.docker.container.image.v1+json",
      "lastRecordedPullTime": "2024-04-24T08:55:56.071000+02:00"
    },
    {
      "registryId": "259611133533",
      "repositoryName": "core",
      "imageDigest": "sha256:39239ba86a543aa6787da0a02479d6f59eb00742e4810a9d4b52f1423a5e0392",
      "imageTags": [
        "master-202404260911"
      ],
      "imageSizeInBytes": 470843809,
      "imagePushedAt": "2024-04-26T11:12:51+02:00",
      "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "artifactMediaType": "application/vnd.docker.container.image.v1+json",
      "lastRecordedPullTime": "2024-04-26T11:14:06.695000+02:00"
    }
  ]
}

And I want to filter the dataset by imagePushedAt and imageTags, which should contain the string master.
I've tested the following

imageDetails[?imagePushedAt<`2024-04-27` && imageTags.contains(@, `master`)]

But, unfortunately this doesn't work.
I, in some way, got what I wanted by using this query

imageDetails[?imagePushedAt < `2024-04-27`] | [].imageTags[?contains(@,`master`)]

but, this solution returns an empty array when the imageTags doesn't match instead of filtering out the result.


Solution

  • Since imageTags is an array, imageTags.contains(@, `master`) would means that you want an element strictly equal to master in your imageTags array, while what you mean is "for each element of the array, I want the element(s) that does contain master".

    The later can be expressed via

    imageTags[?contains(@, `master`)]
    

    Because, while the @ represent an element of the array, when applied to the array itself, here, it is applied as a filter, to each element of the array, so the @ now represent each string of the imageTags array.

    So, your whole query ends up being:

    imageDetails[?
      imagePushedAt < `2024-04-27` 
      && imageTags[?contains(@, `master`)]
    ]
    

    Which would, on your example JSON, yield a single element:

    [
      {
        "registryId": "259611133533",
        "repositoryName": "core",
        "imageDigest": "sha256:39239ba86a543aa6787da0a02479d6f59eb00742e4810a9d4b52f1423a5e0392",
        "imageTags": [
          "master-202404260911"
        ],
        "imageSizeInBytes": 470843809,
        "imagePushedAt": "2024-04-26T11:12:51+02:00",
        "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
        "artifactMediaType": "application/vnd.docker.container.image.v1+json",
        "lastRecordedPullTime": "2024-04-26T11:14:06.695000+02:00"
      }
    ]