How to select elements in jq based on value in array

I have a file with these lines:

{"items":["blue","green"]} {"items":["yellow","green"]} {"items":["blue","pink"]} 

How can I use jq to select and display only JSON values ​​that have "blue" in their "items" array?

Thus, the output will be:

 {"items":["blue","green"]} {"items":["blue","pink"]} 
+11
source share
4 answers

Although what you are definitely working on, it would be better to use contains . I would avoid this use as it can lead to confusion. index("blue") is 0 , and no one considers this a plausible value and can expect it to be excluded from the results.

Use this filter instead:

 select(.items | contains(["blue"])) 

This has the added benefit that it will work if you need elements with multiple matches, just adding more to the array. Strike>

As stated in the comments, this is not entirely correct. Strings are compared using a substring ( contains used recursively) here.

In retrospect, contains did not work as I thought. Using index works, but personally, I would not use it. There is something to figure out if there is an item in the collection by looking for its index, which I don't like. Using contains makes more sense to me, but in the light of this information in this case it will not be ideal.


Here is an alternative that should work correctly:

 select([.items[] == "blue"] | any) 

Or for a more scalable way, if you want to be able to match more values:

 select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all) 
+3
source

Found an answer

 jq 'select(.items | index("blue"))' 
+5
source

On January 30, 2017, a built-in IN function was added to effectively check for the presence of a JSON entity in the stream. It can also be used to effectively test array membership. In this case, the appropriate use will be:

 select( .items as $items | "blue" | IN($items[]) ) 

If your jq does not have IN/1 , then as 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; 

any / 0

Using any/0 here is relatively inefficient, for example, compared to using any/0 :

 select( any( .items[]; . == "blue" )) 

(In practice, index/1 usually quite fast, but its implementation at present (jq 1.5 and versions at least until July 2017) is not optimal.)

+2
source

I needed to use "regular expression" for the same situation of objects. (In a different context, of course). I write code because I did not find a solution for my needs on these pages. This may be helpful for someone.

For example, to match blue using a regular expression:

 jq 'select(.items[]|test("bl.*"))' yourfile.json 

jqPlay

0
source

Source: https://habr.com/ru/post/974764/


All Articles