jq find the max in quoted values
Asked Answered
D

2

5

Here is my JSON test.jsonfile :

[
  {
    "name": "nodejs",
    "version": "0.1.21",
    "apiVersion": "v1"
  },
  {
    "name": "nodejs",
    "version": "0.1.20",
    "apiVersion": "v1"
  },
  {
    "name": "nodejs",
    "version": "0.1.11",
    "apiVersion": "v1"
  },
  {
    "name": "nodejs",
    "version": "0.1.9",
    "apiVersion": "v1"
  },
  {
    "name": "nodejs",
    "version": "0.1.8",
    "apiVersion": "v1"
  }
]

When I use max_by, jq return 0.1.9 instead of 0.1.21 probably due to the quoted value :

cat test.json | jq 'max_by(.version)'
{
  "name": "nodejs",
  "version": "0.1.9",
  "apiVersion": "v1"
}

How can I get the element with version=0.1.21 ?

Disseisin answered 17/7, 2019 at 8:0 Comment(0)
T
4

Semantic version compare is not supported out of the box in jq. You need to play around with the fields split by .

jq 'sort_by(.version | split(".") | map(tonumber))[-1]'

The split(".") takes the string from .version and creates an array of fields i.e. 0.1.21 becomes an array of [ "0", "1", "21"] and map(tonumber) takes an input array and transforms the string elements to an array of digits.

The sort_by() function does a index wise comparison for each of the elements in the array generated from last step and sorts in the ascending order with the object containing the version 0.1.21 at the last. The notation [-1] is to get the last object from this sorted array.

Tradein answered 17/7, 2019 at 8:8 Comment(2)
nice one line answer. I tested with other value like 0.2.1 or 11.7 and it works in all cases. ThxDisseisin
One could simply use max_by.Zoophilous
Z
2

Here's an adaptation of the more general answer using jq at How to sort Artifactory package search result by version number with JFrog CLI?

def parse:
 [splits("[-.]")]
 | map(tonumber? // .) ;

max_by(.version|parse)

As a less robust one-liner:

max_by(.version | [splits("[.]")] | map(tonumber))
Zoophilous answered 17/7, 2019 at 8:18 Comment(4)
this is also useful for sorting ipv4 addresses. i am kind of stuck trying to sort an ipv6 address, there is no 'tobase16'Swayback
@Swayback - See rosettacode.org/wiki/Non-decimal_radices/Convert#jqZoophilous
nice! thanks. btw, to make that one-liner work I had to add: max_by(.version|[splits("[.]")] | map(tonumber))Swayback
@greg: Fixed. Thank you.Zoophilous

© 2022 - 2024 — McMap. All rights reserved.