1

Select objects based on value of variable in object using jq

That shows how to return values directly above the selection criteria but how would I get another object that was adjacent to a value above my selection criteria?

Given the data below, what jq invocation would return the French name of planets whose moon(s) have been spoiled? (this is a structural reproduction of the live data with which I am working -- which actually uses the word "value" in this way, so that's not helping)

{"kind":"solarsystem","name":"Sol",
"Planets": [
 { "kind":"habitable",
  "names": { "english":"Earth","french":"Terre"},
  "satellites" : [
    {"name":"The Moon",
     "parameters": [
       {"name":"diameter", "intValue":"3476"},
       {"name":"diameter_units", "value":"km"},
       {"name":"unspoiled","value":"no"}]}]},
 {"kind":"uninhabitable",
  "names": {"english":"Mars","french":"Mars"},
  "satellites" : [
    {"name":"Phobos",
     "parameters": [
       {"name":"diameter", "intValue":"2200"},
       {"name":"diameter_units", "value":"m"},
       {"name":"unspoiled","value":"yes"}]},
    {"name":"Deimos",
     "parameters": [
       {"name":"diameter", "intValue":"1200"},
       {"name":"diameter_units", "value":"m"},
       {"name":"unspoiled","value":"yes"}]}]}]}
peak
  • 105,803
  • 17
  • 152
  • 177
FrinkLabs
  • 71
  • 1
  • 4
  • What is the criteria for identifying `have been spoiled?`, i.e. there is no json record with name as `"spoiled"` in the above post – Inian Dec 21 '20 at 06:40
  • On second glance, do you mean `{"name":"unspoiled","value":"no"}` as the criterion? – Inian Dec 21 '20 at 06:42
  • Thanks! I figured it was going to be simple but powerful. And yeah I could have worded it better; I was trying to think of something that duplicated the structure of my data. It reads like Don't Do What Donny Don't Does – FrinkLabs Dec 21 '20 at 06:59

2 Answers2

2

The program below selects planets whose moons have all been spoiled. As each parameter is a name-value pair, we can use from_entries to transform the array of parameters into an object and retrieve the unspoiled status with just .unspoiled, and thus avoid another select to find the parameter we're interested in.

.Planets[] | select(.satellites | all(.parameters | from_entries .unspoiled == "no")) .names.french

If a single spoiled moon is enough, change all to any.

Online demo

oguz ismail
  • 1
  • 16
  • 47
  • 69
1

And here, also a solution for the same JSON query using an alternative tool (jtc):

In the simplest form, the following will do:

bash $ <file.json jtc -w'[value]:<no>:[-5][names][french]'
"Terre"

However, that solution will return planet's french name for each of the moon, e.g., for spoiled moons it would give this:

bash $ <file.json jtc -w'[value]:<yes>:[-5][names][french]'
"Mars"
"Mars"
bash $ 

For the case when there're multiple moons but the name is required only once, strengthen the query like this (showcasing here spoiled moons):

bash $ <file.json jtc -w'<satellites>l:[value]:<yes>[-5][names][french]'
"Mars"
bash $ 

PS. I'm a deveoper of jtc unix JSON processor
PPS. the above disclaimer is required by SO.

Update:

the answer was updated based on discussion in comments with @oguzismail to enhance structural relationship between value and french labels so that other (irrelevant) possible value matches won't trigger false positives.
If, by a chance, the structural relation [-5][names] is not enough, the query then can be ultimately enhanced by inserting <unspoiled>[-1] before [value]... lexeme

Dmitry
  • 1,275
  • 1
  • 5
  • 14
  • Before I upvote this, what is `-5` for? You're not hardcoding the index of parameter `unspoiled`, right? – oguz ismail Dec 26 '20 at 05:27
  • Oguz, in `jtc` negative indices provide addressing of parents from currently found elements toward the root. E.g.: -1 addresses an immediate parent, -2 - a parent of a parent, etc. For given data structure, -5 is a depth required to get to the found `value` element to the parent holding `french`. Considering the structure of this JSON is fixed, hardcoding the _depth_ parameter is safe. – Dmitry Dec 26 '20 at 09:17
  • I agree that it is. What's bugging me is that I can't see `unspoiled` in any of these invocations. OP's sample doesn't contain any parameters that also take yes/no as value, but I'm not sure if assuming that the actual data aligns in that with the sample in the question is also safe. – oguz ismail Dec 26 '20 at 09:21
  • 1
    The answer was provided based on a given sample. If the original JSON contain `value` label in other parts of JSON, the query can be easily enhanced by prepending `[-1]` – Dmitry Dec 26 '20 at 09:29
  • Now that's nice, if I were you I would include that in my answer. – oguz ismail Dec 26 '20 at 09:31
  • However, even if the original JSON contained `value` labels in other parts, most likely the query would work even w/o that enhancing: relation between the value and french labels is unique enough to ensure correctness of the query. You may try throwing random value labels - it’ll still work correctly. – Dmitry Dec 26 '20 at 09:37