JQ - Handling null values and default values

2024-09-15

When working with JSON data using jq, handling null values, missing keys, nested fields, and default values is crucial for writing robust scripts. In this post, we'll explore how to manage these cases effectively.

Handling Null Values in JSON Input

When a JSON field contains a null value, jq treats it as null. You can use the // operator to provide a default value in such cases. In the following example, we check for a null value and provide a default:

jq '.age // 18' input.json

Given an input JSON like this:

{
  "name": "Alice",
  "age": null
}

If .age is null, the output will be 18; otherwise, it will return the actual value.

Handling Absent Keys

If a key is not present in the JSON input, jq will return null when accessing it. To avoid unexpected null results, you can check for the presence of a key using the has function.

Here's how you can provide a default value when a key is absent:

jq 'if has("age") then .age else 18 end' input.json

Given an input JSON like this:

{
  "name": "Alice"
}

This expression checks if the "age" key exists. If it does, it returns the value; otherwise, it defaults to 18.

Handling Nested Fields

When working with nested fields, both the parent and child fields may be missing or null. Combining the ?. operator with the // operator allows handling these cases gracefully.

In the following example, we handle the scenario where nested fields may be missing:

jq '.user?.details?.age // 18' input.json

Given an input JSON like this:

{
  "user": {
    "details": {
      "name": "Alice"
    }
  }
}

If .user, .user.details, or .user.details.age is null or does not exist, the expression defaults to 18.

Providing Default Values Based on Data Type

You might want to set default values based on the expected type of a field (e.g., string, integer, boolean).

The jq conditionals allow you to specify defaults for different data types. In the following example, we provide defaults for multiple types:

jq '{
  name: .name // "Unknown",
  age: .age // 0,
  active: .active // false
}' input.json

Given an input JSON like this:

{
  "name": null,
  "age": null,
  "active": null
}

This expression sets "Unknown" for strings, 0 for integers, and false for booleans if the original values are null.

Nested Defaults with Multiple Levels

Handling multiple levels of nested fields may require combining several techniques. Here, we demonstrate handling missing or null values in deeply nested fields using both the // operator and conditional expressions:

jq '.user.details.address // "No address provided"' input.json

Given an input JSON like this:

{
  "user": {
    "details": {
      "address": null
    }
  }
}

If .user.details.address is null or missing, the output will be "No address provided".