Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jq: select when values from another array match value in this json

Tags:

json

regex

bash

jq

Given json:

[
  {
    "path": "Module1/",
    "users": [
      "john",
      "jane"
    ]
  },
  {
    "path": "Module2/",
    "users": [
      "mike",
      "mary"
    ]
  },
  {
    "path": "Module3/",
    "users": [
      "billy",
      "bonny"
    ]
  }
]

Given array of files:

[
  "Module1/file.java",
  "Module3/file.java"
]

How can I get the users for which any of the files match the path?

Expected output:

[
  "john",
  "jane",
  "billy",
  "bonny"
]

I recently found this answer to a similar question, which cleverly builds regex filter and passes as arg in jq: https://stackoverflow.com/a/54630000/8784215

I set up similarly:

users='[{"path":"Module1/","users":["john","jane"]},{"path":"Module2/","users":["mike","mary"]},{"path":"Module3/","users":["billy","bonny"]}]'
files='["Module1/file.java","Module3/file.java"]'
filter=($(echo $files | jq -r  '. | join(" ")'))
echo $users | jq --arg re "$(IFS="|"; echo "${filter[*]}")" '[.[] | select(.path | test($re)) | .users[]]'

But the problem is that path is being matched against file, when it should be the other way around.

Any ideas?

like image 838
Cody Avatar asked Oct 28 '25 22:10

Cody


1 Answers

You can use ìnside to flip arguments for a contains test which performs a substring matching. Use any to select on first match, and input to read the second input (array of files):

jq 'input as $f | map(select(any(.path | inside($f[]); .)).users[])' input.json files.json
[
  "john",
  "jane",
  "billy",
  "bonny"
]

Demo

like image 128
pmf Avatar answered Oct 30 '25 13:10

pmf