2

I have a json file that essentially looks like this:

{
    "input": {
        "user": "john",
        "group": "johns_group"
    },
    "group_data": [
        {
            "name": "johns_group",
            "members": ["john", "michael"]
        },
        {
            "name": "sallys_group",
            "members": ["sally", "jane"]
        }
    ]
}

Is it possible for me to retrieve the group under group_data with the name specified in input.group using jmespath?

I've tried the following:

group_data[?contains(name, input.group)]

But it doesn't work. If I just put in the group name however:

group_data[?contains(name, 'johns_group')]

It does work. But I can't just hardcode the names because the group_data, input.user, and input.group can all change.

If this isn't possible in pure jmespath with the way I've set it up, I have control over the structure of group_data and can change it to be more jmespath friendly. My end goal is to be able to retrieve the group object and then return a bool if input.user is in its members list.

Anderson-A
  • 74
  • 1
  • 6
  • 1
    `group_data[?contains(name, input.group)]` actually means that you want to query the parent as `input.group` is located in the parent of `group_data`. The issue of not being able to query an object parent is a long standing issue, [as pointed by this answer of 2016 by the maintainer itself](https://stackoverflow.com/a/28681315/2123530). So what you are looking to do is not possible. – β.εηοιτ.βε Aug 09 '23 at 22:52

1 Answers1

1

Short answer: It is not possible.

Details:

  • If you enter group_data you don't see other dictionaries at the same level anymore. You have to put such a reference into a variable, I think. For example, in Python
import jmespath
import json
import yaml


with open('data.json', 'r') as myfile:
    data = myfile.read()
s = json.loads(data)
result = jmespath.search(f"group_data[?name == `{s['input']['group']}`].members", s)
print(yaml.dump(result))

gives (in YAML)

- - john
  - michael

In a shell, you can write a filter. For example,

shell> cat filter.sh
#!/bin/sh
data=`paste -`
input_group=$(echo $data | jp -u "input.group")
group_data=$(echo $data | jp -u "group_data[?name == '$input_group'].members")
printf "$group_data"

which gives the same result (in JSON)

shell> cat data.json | ./filter.sh
[
  [
    "john",
    "michael"
  ]
]
  • You say you can change the structure. Dictionaries in group_data would serve the use-case better, I think
shell> cat data-dict.json
    {
        "group_data": {
            "johns_group": [
                "john",
                "michael"
            ],
            "sallys_group": [
                "sally",
                "jane"
            ]
        },
        "input": {
            "group": "johns_group",
            "user": "john"
        }
    }

You can reference the value without jmespath. For example, in Python

with open('data-dict.json', 'r') as myfile:
    data = myfile.read()
s = json.loads(data)
print(yaml.dump(s))

result = s['group_data'][s['input']['group']]
print(yaml.dump(result))

gives

- john
- michael
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Not quite what I was looking for, need to be able to do it just inside of jmespath and not use any python. – Anderson-A Aug 07 '23 at 17:00
  • Unfortunately, it is not possible. I added a short answer to make it clear that this is not what you were looking for. The rest of the answer describes what is possible. – Vladimir Botka Aug 07 '23 at 18:41