Jennifer M.
Jennifer M.

Reputation: 1662

How to combine the sequence of objects in jq into one object?

I would like to convert the stream of objects:

{
  "a": "green",
  "b": "white"
}
{
  "a": "red",
  "c": "purple"
}

into one object:

{
  "a": "red",
  "b": "white",
  "c": "purple"
}

Also, how can I wrap the same sequence into an array?

[
    {
      "a": "green",
      "b": "white"
    },
    {
      "a": "red",
      "c": "purple"
    }
]

Sadly, the manual is seriously lacking in comprehensiveness, and googling doesn't find the answers either.

Upvotes: 107

Views: 77930

Answers (5)

Chris
Chris

Reputation: 31206

I ran into these answers (Q2 2024) and had to tinker to get it working on jq-1.6.

Given a series of objects:

# objects.json
{ "foo": "bar" }
{ "biz": "baz" }

I was able to embed them within some other custom object like so:

# Type I: single object

cat objects.json \
 | jq -ns '{ type: "something", subtype: "specific", content: (inputs | add) }'  
# Type II: list object

cat objects.json \
 | jq -ns '{ type: "something", subtype: "specific", content: [inputs] }'  

In particular, Type I was where I had to tinker.

Upvotes: 0

peak
peak

Reputation: 116750

If your input is a stream of objects, then unless your jq has inputs, the objects must be "slurped", e.g. using the -s command-line option, in order to combine them.

Thus one way to combine objects in the input stream is to use:

jq -s add

For the second problem, creating an array:

jq -s .

There are of course other alternatives, but these are simple and do not require the most recent version of jq. With jq 1.5 and later, you can use 'inputs', e.g. jq -n '[inputs]'

Efficient solution

For the first problem (reduction), rather than slurping (whether via the -s option, or using [inputs]), it would be more efficient to use reduce with inputs and the -n command-line option. For example, to combine the stream of objects into a single object:

jq -n 'reduce inputs as $in (null; . + $in)'

Equivalently, without --null-input:

jq 'reduce inputs as $in (.; . + $in)

Upvotes: 148

ggorlen
ggorlen

Reputation: 56965

If you got to this point via jq filter rather than external input, mwag's comment suggesting wrapping your jq filter in []s might be useful.

Example:

$ echo '[{"foo":42},{"foo":43}]' | jq '.[]'
{
  "foo": 42
}
{
  "foo": 43
}
$ echo '[{"foo":42},{"foo":43}]' | jq '[.[]]'
[
  {
    "foo": 42
  },
  {
    "foo": 43
  }
]

See also jq Github issue #684: Creating an array from objects?.

Upvotes: 12

Trane9991
Trane9991

Reputation: 385

To combine objects into an array you can use the following:

$ echo '
{
  "a": "green",
  "b": "white"
}
{
  "a": "red",
  "c": "purple"
}' | jq -n '[inputs]'
[
  {
    "a": "green",
    "b": "white"
  },
  {
    "a": "red",
    "c": "purple"
  }
]

Upvotes: 9

Evgeny Zislis
Evgeny Zislis

Reputation: 6957

An alternative to slurping using the -s command-line option is to use the inputs filter. Like so:

jq -n '[inputs] | add'

This will produce an object with all the input objects combined.

Upvotes: 45

Related Questions