Reputation: 13877
I've a large JSON file where I'd like to transform some values based on some kind of mapping.
The data I have looks like:
[
{"id":1, "value":"yes"},
{"id":2, "value":"no"},
{"id":3, "value":"maybe"}
]
And I'd like to transform that into a list like this:
[
{"id":1, "value":"10"},
{"id":2, "value":"0"},
{"id":3, "value":"5"}
]
With the fixed mapping:
yes => 10
no => 0
maybe => 5
My current solution is based on a simple if-elif-else
combination like this:
cat data.json| jq '.data[] | .value = (if .value == "yes" then "10" elif .value == "maybe" then "5" else "0" end)'
But this is really ugly and I'd love to have a more direct way to express the mapping.
Thanks for your help
Upvotes: 4
Views: 12672
Reputation: 1573
using a jq custom function to translate a value of an array of objects:
jq 'def fnYN:
if . == true or . == "true" then "yes"
elif . == false or . == "false" then "no"
else "unknown"
end;
. | map(.value |= fnYN)
| [ .[] | { id, value } ]
'
input:
[
{"id":1, "value":true},
{"id":2, "value":"false"},
{"id":3, "value":"maybe"}
]
result:
[
{"id": 1, "value": "yes"},
{"id": 2, "value": "no"},
{"id": 3, "value": "unknown"}
]
Upvotes: 0
Reputation: 14715
Here is a solution which uses an "inline" object since the mapping is small:
map(.value = {"yes":"10","no":"0","maybe":"5"}[.value])
which can be shorted with |=
as in peak's solution to:
map(.value |= {"yes":"10","no":"0","maybe":"5"}[.])
Upvotes: 3
Reputation: 116957
If one wants to avoid having to specify the mapping on the command line, then the following two variants may be of interest.
The first variant can be used with jq 1.3, jq 1.4 and jq 1.5:
def mapping: {"yes":"10","no":"0","maybe":"5"};
map(.value |= mapping[.])
The next variant uses the --argfile option (available since jq 1.4), and is of interest if the mapping object is available in a file:
jq --argfile mapping mapping.jq 'map(.value |= $mapping[.])' data.json
Finally, in jq 1.5, other alternatives based on import are also available (!).
Upvotes: 5
Reputation: 134571
Since you're translating string values, you should be able to use a json object to hold the mappings. Then mapping would be trivial.
$ jq --arg mapping '{"yes":"10","no":"0","maybe":"5"}'
'map(.value |= ($mapping | fromjson)[.])' data.json
Upvotes: 1