3

I'm trying to create a jq filter for JSON, similar to How to filter an array of objects based on values in an inner array with jq? - but even using that as a basis doesn't seem to be giving me the results I want.

Here's my example json

[{"id":"0001","tags":["one","two"]},{"id":"0002", "tags":["two"]}]

I want to return a list of IDs where tags contains "one" (not partial string match, full element match).

I have tried some variations, but can't get the filter right.

. - map(select(.resources[] | contains("one"))) | .[] .id

Returns "0001","0002"

Have also tried ... .resources[].one)) | ... but always get full list when trying to filter by "one" and expecting to only get 0001

Where am I filtering wrong? (have about 30 minutes experience with jq, so please excuse my ignorance if it's something obvious :)

peak
  • 105,803
  • 17
  • 152
  • 177
Brett
  • 5,690
  • 6
  • 36
  • 63

1 Answers1

5
map(select(.tags | index("one")) | .id)

Since your problem description indicates you want to check if the array contains "one", it's simplest to use index.

UPDATE

On Jan 30, 2017, a builtin named IN was added for efficiently testing whether a JSON entity is contained in a stream. It can also be used for efficiently testing membership in an array. In the present case, the relevant usage would be:

map(select(.tags as $tags | "one" | IN($tags[])) | .id)

If your jq does not have IN/1, then so long as your jq has first/1, you can use this equivalent definition:

def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;

(In practice, index/1 is usually fast enough, but its implementation currently (jq 1.5 and versions through at least July 2017) is suboptimal.)

peak
  • 105,803
  • 17
  • 152
  • 177
  • I don't see `index` has a predefined function. Looking through the docs, it looks like `in` might be a function that would help. However, using in gives me errors - `error: in is not defined`. jq --version is 1.3 – Brett Aug 06 '15 at 08:20
  • Downloaded jq 1.4 and index works. Turns out that I wasn't expecting my output properly, and `contains` and `index` are giving the same result: the inverse of what I'm expecting. I get a list of ID's that DONT contain the specified tag. – Brett Aug 06 '15 at 08:44
  • I had a `-` at the start of my expression. when I dropped it and used your expression as-is, it actually does work @peak. marking answer as correct, thanks for your help. – Brett Aug 06 '15 at 08:53