Carlo Corradini
Carlo Corradini

Reputation: 3435

Transform specific fields into array(s) using jq

Given the following JSON:

{
  "one": "1",
  "two": "2",
  "flag": "f1 f2 f3",
  "test one": "",
  "test two": "",
  "test three": ""
}

Is it possible to obtain the following result using jq?

{
  "one": "1",
  "two": "2",
  "flags": ["f1", "f2", "f3"],
  "tests": ["one", "two", "three"]
}

Three points are crucial:

  1. Leave unchanged any field that is not flag or starts with test

  2. Transform flag (space separated values) into an array

  3. Any field that starts with test is added to an array (tests) where the value is the remaining part of the field's name

Upvotes: 0

Views: 607

Answers (1)

pmf
pmf

Reputation: 36646

You can use /= to update by splitting, startswith to match at the beginnning of a string, and to_entries and with_entries to manipulate entries involving the key name:

jq '
  .flag /= " "
  | .tests = (to_entries | map(.key | select(startswith("test "))[5:]))
  | with_entries(select(.key | startswith("test ") | not))
'

Demo


Another, maybe more efficient implementation which loops just once through the object using reduce could be:

jq '
  reduce to_entries[] as {$key, $value} (null;
    if   $key == "flag"             then .flag = $value / " "
    elif $key | startswith("test ") then .tests += [$key[5:]]
    else                                 .[$key] = $value end
  )
'

Demo


Given the sample data, both produce:

{
  "one": "1",
  "two": "2",
  "flag": [
    "f1",
    "f2",
    "f3"
  ],
  "tests": [
    "one",
    "two",
    "three"
  ]
}

Upvotes: 2

Related Questions