1. Overview

In this tutorial, we’ll discuss how to add a JSON object to a JSON array in another file. For that purpose, we’ll make use of the jq utility.

We’ll begin by understanding the problem and then work our way down to several possible solutions.

2. The Problem

Suppose we have two files named post.json and blog.json. The post.json file contains a single JSON object that needs to be added to a JSON array posts inside the blog.json file, which looks like this:

{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": []
}

On the other hand, post.json is a simple JSON object:

{
  "author": "Jane Smith",
  "published": "2023-10-11",
  "content": "This is a short example blog post."
}

Now, there are several ways to accomplish this. For instance, we can write a simple Python or Ruby script to do this. However, we can do this jq as well, which is a performant command-line tool to process JSON data.

In the next sections, we’ll use jq to discuss different approaches to solving this problem.

3. Possible Solutions

jq is quite simple. It has several options for the problem at hand. However, each of these options is suitable for different scenarios. Let’s dive into it.

3.1. –argjson

–argjson is a jq flag that passes a JSON object as a variable to jq filter, thereby allowing us to use variables in jq queries when working with JSON data.

Here’s a simple –argjson  syntax:

$ jq --argjson [variable_name] "{ ... }" 'jq_filter' [json_file]

Let’s break this down:

  • –argjson expects a variable name, and the JSON data
  • object “{ … }” is set to the variable name
  • ‘jq_filter’ is where we use the variable
  • <JSON> is the JSON file on which we’re operating

So, with this approach, we can add the object from post.json to the posts array:

$ POST=$(<post.json) jq --argjson p "$POST" '.posts += [$p]' blog.json

Let’s see how it works:

  • POST holds the contents read from post.json
  • –argjson p $POST passes the content of the POST variable to p
  • ‘.posts += [$p]’ is the jq filter to update the posts array:
    • .posts selects the posts field
    • += appends to the array
    • [$p] puts the contents of p into the array
  • blog.json is the JSON file on which we’re operating

Here’s the output:

{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": [
    {
      "author": "Jane Smith",
      "published": "2023-10-11",
      "content": "This is a short example blog post."
    }
  ]
}

Alternatively, we can shorten the command:

$ jq --argjson p "$(<post.json)" '.posts += [$p]' blog.json

Here, we omit the POST variable and write the contents of post.json directly to the p variable. In addition, if we have multiple JSON files like post-1.jsonpost-2.json, and so on, we can write a simple shell script to add them to posts:

#!/bin/bash

blog="$(<blog.json)"
for json in post-*.json; do
  blog="$(echo "$blog" | jq --argjson p "$(<$json)" '.posts += [$p]')"
done

echo "$blog"

This –argjson method should work very well on most shells. However, we should know that the $(<file) construct is limited to bash, zsh, and ksh. Therefore, we should use cat to make it POSIX compliant.

3.2. input and inputs

The input function in jq reads contents from stdin or files specified to jq. Similarly, the inputs function can read multiple files.

Therefore, we can feed the post.json file to jq:

$ jq '.posts += [input]' blog.json post.json

Here’s the output:

{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": [
    {
      "author": "Jane Smith",
      "published": "2023-10-11",
      "content": "This is a short example blog post."
    }
  ]
}

jq parses the filter, and as soon as it encounters input, it looks for the next file given as input. In this case, it reads the contents of post.json. Similarly, if we have another input function in the filter, jq reads the corresponding file.

The inputs function works in the same way, except that it reads all the files after the first one:

$ jq '.posts += [inputs]' blog.json post-1.json post-2.json

Once executed, it produces a JSON with all the posts inside the array:

{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": [
    {
      "author": "Jane Smith",
      "published": "2023-10-11",
      "content": "This is a short example blog post."
    },
    {
      "author": "John Doe",
      "published": "2023-07-03",
      "content": "This is demo blog content."
    }
  ]
}

Notably, we don’t need to put a comma after each object, as jq takes care of it.

This approach works well in scenarios where we have the JSON files on the disk. However, it requires workarounds to make it suitable for JSON files that are fetched from remote sources.

3.3. –slurpfile

The –slurpfile option in jq is another way to read and process a JSON object from a file:

$ jq '.posts = $inputs' blog.json --slurpfile inputs post-1.json
{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": [
    {
      "author": "Jane Smith",
      "published": "2023-10-11",
      "content": "This is a short example blog post."
    }
  ]
}

Let’s break this down:

  • –slurpfile inputs stores the content of post-1.json into the inputs variable
  • $inputs in the jq filter expands to the value it holds

Additionally, let’s say we have a single JSON containing multiple posts in an array:

$ jq -s '.' post-1.json post-2.json | tee posts.json
[
  {
    "author": "Jane Smith",
    "published": "2023-10-11",
    "content": "This is a short example blog post."
  },
  {
    "author": "John Doe",
    "published": "2023-07-03",
    "content": "This is demo blog content."
  }
]

We can put the posts objects from posts.json into the posts array in blogs.json:

$ jq '.posts += $inputs[]' blog.json --slurpfile inputs posts.json
{
  "title": "Baeldung",
  "author": "John Doe",
  "domain": "baeldung.com",
  "posts": [
    {
      "author": "Jane Smith",
      "published": "2023-10-11",
      "content": "This is a short example blog post."
    },
    {
      "author": "John Doe",
      "published": "2023-07-03",
      "content": "This is demo blog content."
    }
  ]
}

As we can see, posts in blog.json is an array, but so is posts.json. Therefore, instead of nesting the array from posts.json into the posts array in blog.json, we used the $inputs[] notation.

The $inputs[] construct effectively concatenates the contents of inputs as a flat array directly into posts in blog.json. This results in a single array.

4. Conclusion

In this article, we explored the various ways we can add an object to a JSON array using jq. With a hands-on approach, we used several techniques, such as using the –argjson flag, input and inputs functions, and the –slurpfile option.