'Use yq4 to move everything under one key to another path in the yaml

I have a yaml of the following format:

car_facts:
 colour: 'red'
 spec: 
   tyres: 4
vehicles: 
  tractor:
    speed: 'slow'
  car:
    speed: 'fast' 

I'm looking for a yq4 command that will move everything under car_facts inplace to a new field in the yaml (car). Ideally, it would remove the exisiting field too (although this could be done using the delete operator in a follow-up command). So the target state would be:

vehicles: 
  tractor:
    speed: 'slow'
  car:
    speed: 'fast'
    colour: 'red'
    spec: 
      tyres: 4

As with this example, the fields under the original key may be nested. In my case, there is no chance of path of the original keys existing under the destination.

I've looked through the docs but haven't seen an example for this specific case.

I've tried yq4 -- eval --inplace '.car_facts.[] +=.vehicles.car' but that returns Error: Maps not yet supported for addition.



Solution 1:[1]

This is not yet supported in mikefarah/yq implementation yet, as addition or merge operations on map types is not available.

But Python yq supports it out of the box, as the underlying jq supports the operation on JSON type. Since this yq is just a wrapper over jq, all the operations are performed on the JSON with jq and converted back to YAML. So something like below should work

yq -Y --in-place '.vehicles.car += .car_facts | del(.car_facts)'  yaml

Solution 2:[2]

This is now possible to do using the new with operator, added in version 4.13.0.

https://mikefarah.gitbook.io/yq/operators/with

sample.yml
car_facts:
 colour: 'red'
 spec: 
   tyres: 4
vehicles: 
  tractor:
    speed: 'slow'
  car:
    speed: 'fast' 
command
yq4 '{"vehicles":.vehicles} as $root |
     {"car":.car_facts} as $car |
     with($root.vehicles; . |= . *+ $car) |
     $root' sample.yml
  1. First, create a new $root variable, containing the original vehicles map.
  2. Then, create a new $car variable, containing the original car_facts map.
  3. Then, merge the $car variable into the $root.vehicles map.
  4. Finally, output the merged $root variable.
output
vehicles:
  tractor:
    speed: 'slow'
  car:
    speed: 'fast'
    colour: 'red'
    spec:
      tyres: 4

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Inian
Solution 2