91

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.

peak
  • 105,803
  • 17
  • 152
  • 177
Jennifer M.
  • 1,398
  • 1
  • 9
  • 11
  • 5
    how did you get this input to begin with? is the sequence being created by a jq command that is being filtered through something like .[], or is it really the original state of the input you are getting? If the former, which is very often the case when starting with valid JSON, then the jq command that resulted in the sequence can probably be easily modified to output an array by surrounding the iterative processing command with [ and ], rather than having to pipe two jq commands together, the second of which would use -s – mwag Apr 17 '17 at 20:57

4 Answers4

133

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)
peak
  • 105,803
  • 17
  • 152
  • 177
  • 18
    @JenniferM. Instead of leaving a *Thanks* comment you can also [Accept an answer](http://stackoverflow.com/help/someone-answers) – rene Jan 01 '16 at 11:41
  • 1
    How about when the sequence shows up as the result of an expression.. ? as ` | add` doesn't quite do what I want.. – Kaos Oct 27 '16 at 08:04
  • 5
    Ok, I just needed to post that to figure out how to do it. I turned my `.[] | | add` into `. | map() | add` and now it does what I want ;) – Kaos Oct 27 '16 at 08:08
41

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.

peak
  • 105,803
  • 17
  • 152
  • 177
Evgeny
  • 6,533
  • 5
  • 58
  • 64
9

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?.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
6

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"
  }
]
Trane9991
  • 326
  • 3
  • 8
  • 1
    Your answer is valid, but has no discernible advantage over the simpler (shorter) answer already given elsewhere on this page (`jq -s .`); in this case, simply using -s might actually be faster as the processing done by -s is all written in C. – peak Nov 20 '20 at 03:43