Arkaik
Arkaik

Reputation: 902

jq - Filtering JSON array if does not contains not working

I'm having trouble parsing a JSON file from which I would like to extract elements that does not contains the string "To Do" as label.

Here is the file I'm trying to parse

[
  {
    "id": 1,
    "title": "Task A",
    "labels": [
      "Low",
      "To Do"
    ]
  },
  {
    "id": 2,
    "title": "Task B",
    "labels": [
      "Medium",
      "Done"
    ]
  },
  {
    "id": 3,
    "title": "Task C",
    "labels": [
      "High",
      "To Do"
    ]
  }
]

I can successfully extract elements which contains "To Do" with the following command :

$ cat tmp.json | jq 'keys[] as $k | select(.[$k].labels[] | contains("To Do")) | "\(.[$k].id) -- \(.[$k].title) -- \(.[$k].labels)"'
"1 -- Task A -- [\"Low\",\"To Do\"]"
"3 -- Task C -- [\"High\",\"To Do\"]"

However when I negate the condition jq has the following behaviour :

$ cat tmp.json | jq 'keys[] as $k | select(.[$k].labels[] | contains("To Do") | not) | "\(.[$k].id) -- \(.[$k].title) -- \(.[$k].labels)"'
"1 -- Task A -- [\"Low\",\"To Do\"]"
"2 -- Task B -- [\"Medium\",\"Done\"]"
"2 -- Task B -- [\"Medium\",\"Done\"]"
"3 -- Task C -- [\"High\",\"To Do\"]"

The only difference here is the condition's negation, but all three elements are printed and the one I want to filter is printed twice.

Thanks.

Upvotes: 3

Views: 1605

Answers (2)

oguz ismail
oguz ismail

Reputation: 50815

Your query seems overcomplicated for such a trivial task (I didn't debug but you're probably misusing contains there; I suspect it's run for each array element, not just once for the array itself).

Anyway, here is a clean and straightforward approach:

.[] | select(.labels | index("To Do") | not) | "\(.id) -- \(.title) -- \(.labels)"

Upvotes: 6

peak
peak

Reputation: 117027

I'd go with all(_; . != "To Do"):

.[] 
| select( all(.labels[]; . != "To Do"))
|  "\(.id) -- \(.title) -- \(.labels)"

Upvotes: 3

Related Questions