How can I spread an object's properties in jq?

Viewed 692

If I need to access the properties of an object, I'm currently accessing each property manually:

echo '{"a": {"a1":1, "a2": 2}, "b": 3}' | jq '{a1:.a.a1, a2: .a.a2,b}'
{
  "a1": 1,
  "a2": 2,
  "b": 3
}

I'd like to avoid specifying every property. Is there an equivalent to the Object spread operator in JS, something like jq '{...a, b}'?

3 Answers

You can add objects together to combine their contents. If a key exists in both the left and right objects the value from the right object will remain.

echo '{"a": {"a1":1, "a2": 2}, "b": 3}' | jq '.a+{b}'
{
  "a1": 1,
  "a2": 2,
  "b": 3
}

If you want a completely generic solution:

[..|objects|with_entries(select(.value|type!="object"))]|add

Or if you want a depth-first approach, replace add by reverse|add.

The above of course comes with the understanding that add resolves conflicts in a lossy way. If you don’t want any lossiness, choose a different method for combining objects, or maybe don’t combine them at all.

Here is a solution that only examines the top-level values, without referring to any key by name:

with_entries(if .value|type=="object" then .value|to_entries[] else . end)

For the example, this produces:

{
  "a1": 1,
  "a2": 2,
  "b": 3
}

Note that even though this solution doesn't use add explicitly, it comes with a similar caveat about key collisions.

Related