0

I am currently learning how to usage jq. I have a json object and I am able to loop and read values with jq as such cat test.json | jq -r '.test'. However, I am running into some complexity when I only want to display on values that have outdated or deprecated = true but ommit from result if relase = never-update-app or never-upgrade-app. I am trying cat test.json | jq '.test | select(.[].outdated==true)' but this is not returning the desired results. Is this something possible through jq and have it display in the below desired format?

My desired output is shown below:

Release Name                                             Installed    Latest    Old      Deprecated
test-app                                                 1.0.0        2.0.0     true     false  

json:

{
    "test": [{
        "release": "myapp1",
        "Installed": {
            "version": "0.3.0",
            "appVersion": "v1.2.6"
        },
        "Latest": {
            "version": "",
            "appVersion": ""
        },
        "outdated": false,
        "deprecated": false
    }, {
        "release": "myapp2",
        "Installed": {
            "version": "6.5.13",
            "appVersion": "1.9.1"
        },
        "Latest": {
            "version": "",
            "appVersion": ""
        },
        "outdated": false,
        "deprecated": false
    }, {
        "release": "test-app",
        "Installed": {
            "version": "1.0.0",
            "appVersion": ""
        },
        "Latest": {
            "version": "2.0.0",
            "appVersion": ""
        },
        "outdated": true,
        "deprecated": false
    }, {
        "release": "never-update-app",
        "Installed": {
            "version": "1.0.0",
            "appVersion": ""
        },
        "Latest": {
            "version": "3.0.0",
            "appVersion": ""
        },
        "outdated": true,
        "deprecated": false
    }, {
        "release": "never-upgrade-app",
        "Installed": {
            "version": "2.0.0",
            "appVersion": ""
        },
        "Latest": {
            "version": "2.0.0",
            "appVersion": ""
        },
        "outdated": false,
        "deprecated": true
    }]
}
MaryCoding
  • 624
  • 1
  • 9
  • 31
  • The input is invalid, missing a comma on line 51 – Benjamin W. Mar 11 '21 at 22:55
  • @BenjaminW. It's corrected now. Thanks! – MaryCoding Mar 11 '21 at 23:12
  • Possible duplicate: https://stackoverflow.com/questions/18592173/select-objects-based-on-value-of-variable-in-object-using-jq The only things different here are that you want to have multiple conditions, and _possibly_ that you want to format the output. Is the formatting part of the question? – Weeble Mar 11 '21 at 23:18
  • Here's a question that addresses having multiple conditions: https://stackoverflow.com/questions/33057420/jq-select-multiple-conditions – Weeble Mar 11 '21 at 23:21
  • @Weeble thank you for pointing me to that. Yes, formatting is part of it too. I can address that in my post – MaryCoding Mar 11 '21 at 23:22
  • And here's an answer that includes formatting into a table using jq's `@tsv` filter and the `column` command-line tool. It is a bit complex though, but I think it's general enough to be useful unless you have _extremely_ specific layout requirements. https://stackoverflow.com/a/54854136/2283 – Weeble Mar 11 '21 at 23:28
  • @Weeble thank you. I am trying these things and now getting different results. In relation to conditions, I tried `cat test.json | jq '.test | select(.[].outdated==true)'` but still get all results to show as if the condition did not apply? – MaryCoding Mar 11 '21 at 23:39

2 Answers2

2

How to act on each element in an array

You have an array in .test. If you want to extract the individual elements of that array to use in the rest of your filter, use .test[]. If you want to process them but keep the results in an array, use .test|map(...) where ... is the filter you want to apply to the elements of the array.

How to filter objects with multiple conditions

As described in this question you can use the select() filter with multiple conditions. So, for example:

jq '.test[]|
    select(
        (.outdated or .deprecated) and
        .release != "never-update-app" and
        .release != "never-upgrade-app"
    )'

How to combine non-trivial filters

Use parentheses! As an example, suppose you want to replace the two "never-" tests with a startswith test. By surrounding the pipes with parentheses you isolated the calculation and just get the true/false answer to combine in a boolean expression.

jq '.test[]|
    select(
        (.outdated or .deprecated) and
        (.release|startswith("never-")|not)
    )'

How to format results in a table

I think this answer on formatting results in a table is probably sufficient. If you have more specific needs I think you might want to spin this off into a separate question.

Weeble
  • 17,058
  • 3
  • 60
  • 75
  • Great. If the `.release` field varies and I want to apply a wildcard or `startswith`. I am able to do this `.release|startswith("never")` but how can I apply or add it to fit in with your answer? – MaryCoding Mar 12 '21 at 00:17
  • Ah, I made a mistake in my haste with the boolean expression. I've updated it and added an example of further modifications. Hopefully that is enough to set you in the right direction. – Weeble Mar 12 '21 at 08:56
0

Filter

(["ReleaseName","Installed","Latest","Old","Deprecated"] | @tsv), (.test[] | select(   (.outdated==true or .deprecated==true) and ((.release=="never-update-app" or .release=="never-upgrade-app") | not)   ) | "\(.release) \(.Installed.version) \(.Latest.version) \(.outdated) \(.deprecated)" / " " | @tsv)

Output

ReleaseName Installed   Latest  Old Deprecated
test-app    1.0.0   2.0.0   true    false

Demo

https://jqplay.org/s/B4a5cxlL28

Logan Lee
  • 807
  • 9
  • 21