Documentation Index

Fetch the complete documentation index at: https://docs.supermetrics.com/llms.txt

Use this file to discover all available pages before exploring further.

Union nested arrays with key

Prev Next

For each parent item under dataPath, the union_nested_arrays_with_key adapter looks up the object at containerPath, treats each of its child keys as a category, and emits one row per entry found inside each category's array. Each emitted row records its source category name under keyName, and the parent item's other (non-container) fields are preserved on every row. Use mode + keys to whitelist or denylist which categories to include.

Use this when an API returns per-category arrays nested under a single object (for example, one array per channel under a messages object) and you want a single flat report tagged with the category name. Stacking flatten_values once per category instead produces a cartesian product across categories.

Field Type Default Required Description
dataPath string $.* Yes JSONPath to the iterable of parent items. The transformed list is written back under this path.
containerPath string Yes JSONPath, relative to each parent item, pointing at the container whose children will be unioned.
keyName string Yes Property name under which each emitted row records its source category key.
mode string include No One of include or exclude. With include, keys is a whitelist; with exclude, keys is a denylist.
keys array [] No Category keys to include or exclude depending on mode. May be empty for include (unions every category); must be non-empty for exclude.

The combinations of mode and keys resolve as follows:

mode keys Behavior
include [] Default — union every category in the container.
include non-empty Whitelist — union only the listed categories.
exclude non-empty Denylist — union every category except the listed ones.
exclude [] Invalid — rejected by the configuration validator.

Note: Non-list siblings of the container (for example, a scalar or object alongside the per-category arrays) are silently skipped — they do not produce rows and do not raise errors.

Below you can find a before/after example. The original response groups variations per channel:

{
  "data": [
    {
      "time": "2024-01-01T00:00:00Z",
      "messages": {
        "email": [
          {
            "variation_name": "v1",
            "sent": 100
          },
          {
            "variation_name": "v2",
            "sent": 80
          }
        ],
        "push": [
          {
            "variation_name": "v1",
            "sent": 50
          }
        ]
      }
    }
  ]
}

After the adapter runs, each variation becomes its own row with the channel tagged on it:

{
  "data": [
    {
      "time": "2024-01-01T00:00:00Z",
      "channel_type": "email",
      "variation_name": "v1",
      "sent": 100
    },
    {
      "time": "2024-01-01T00:00:00Z",
      "channel_type": "email",
      "variation_name": "v2",
      "sent": 80
    },
    {
      "time": "2024-01-01T00:00:00Z",
      "channel_type": "push",
      "variation_name": "v1",
      "sent": 50
    }
  ]
}

Configuration:

"response": {
  "dataRows": {
    "source": "jsonPath",
    "value": "$.data.*"
  },
  "dataAdapters": {
    "items": [
      {
        "type": "union_nested_arrays_with_key",
        "config": {
          "dataPath": "$.data.*",
          "containerPath": "$.messages",
          "keyName": "channel_type"
        }
      }
    ]
  }
}

To include only specific categories, set mode: "include" and list them in keys:

{
  "type": "union_nested_arrays_with_key",
  "config": {
    "dataPath": "$.data.*",
    "containerPath": "$.messages",
    "mode": "include",
    "keys": [
      "email",
      "push"
    ],
    "keyName": "channel_type"
  }
}

To exclude specific categories instead, set mode: "exclude" and list the keys to skip:

{
  "type": "union_nested_arrays_with_key",
  "config": {
    "dataPath": "$.data.*",
    "containerPath": "$.messages",
    "mode": "exclude",
    "keys": [
      "summary",
      "metadata"
    ],
    "keyName": "channel_type"
  }
}

Below you can find example field definitions that read from the transformed structure:

[
  {
    "id": "time",
    "label": "Time",
    "dataType": "string.time.date_time",
    "value": {
      "source": "jsonPath",
      "value": "$.time"
    }
  },
  {
    "id": "channel_type",
    "label": "Channel type",
    "dataType": "string.text.value",
    "value": {
      "source": "jsonPath",
      "value": "$.channel_type"
    }
  },
  {
    "id": "variation_name",
    "label": "Variation name",
    "dataType": "string.text.value",
    "value": {
      "source": "jsonPath",
      "value": "$.variation_name"
    }
  },
  {
    "id": "sent",
    "label": "Sent",
    "dataType": "int.number.value",
    "value": {
      "source": "jsonPath",
      "value": "$.sent"
    }
  }
]