jsonjqnegation

jq combine positive and negative filters with select


Given the following JSON object "test.json":

{
    "results": [
        {"name": "package-dev_0.0.1-dev.er56ut.pkg"},
        {"name": "package-dev_0.0.23-master.qwk89mo.pkg"},
        {"name": "package_0.9.1-dev.til39aw.pkg"},
        {"name": "package_0.3.3-master.mbw80lk.pkg"}
    
    ]
}

I am trying to use jq to filter for instances where the key "name" contains "dev" but does not contain "master" and output the value of "name".

Filtering for instances where the key "name" contains "dev" is fine:

cat test.json | jq '.results[]|select(.name|contains("dev")) | .name'
"package-dev_0.0.1-dev.er56ut.pkg"
"package-dev_0.0.23-master.qwk89mo.pkg"
"package_0.9.1-dev.til39aw.pkg"

But I haven't been successful in removing instances where the key "name" contains "master":

cat test.json | jq '.results[]|select(.name|contains("dev")) | select(.name|contains("master"))|not'
false

Solution

  • Use not, which is a builtin rather than an operator:

    .results[] | select(.name | contains("dev") and (contains("master") | not)) | .name
    
    "package-dev_0.0.1-dev.er56ut.pkg"
    "package_0.9.1-dev.til39aw.pkg"
    

    Demo

    Alternatively, you can collect your tests in an array and test against that

    .results[] | select([.name | contains("dev", "master")] == [true, false]) | .name
    
    "package-dev_0.0.1-dev.er56ut.pkg"
    "package_0.9.1-dev.til39aw.pkg"
    

    Demo