JSON Normalize Input
Description
The JSON Normalize Input transform is similar to JSON Input for sourcing data (file, URL, or a field from a previous transform), but it is built for tabular extraction from JSON documents:
-
A record JsonPath selects an array of objects (or scalar elements). Hop emits one output row per array element.
-
Nested objects under each record are flattened into column paths using a configurable separator (default: a dot, like
customer.namefor nested keys). -
On the Fields tab, each row’s Path is the flattened key (for example
customer.name), not a separate JsonPath query into the raw file.
Use this transform when your JSON has a clear list of entities (orders, events, or a root-level array) and you want a wide, denormalized row set without chaining multiple JSON Input transforms.
|
Choose JSON Input when you need one row per document (or a fixed shape) and each column is filled by its own JsonPath into the file; choose JSON Normalize Input when the document has an array of similar objects and you want one output row per array element with nested objects flattened into dotted column names. |
Why one JSON document can need several JSON Normalize Input transforms
Each transform run picks one Record JsonPath that must resolve to an array. That defines a single output grain: one row per element of that array, with fields taken from that element after flattening.
You often still use several JSON Normalize Input transforms on the same pipeline (in parallel branches or one after another) because:
-
Sibling arrays — One file may hold unrelated lists (for example, in
hop-config.json:variables,lifecycleEnvironments, andprojectConfigurations). Each list has its own element shape; a single record path cannot return two arrays at once. Normalize each list with its own transform (and JsonPath such as$.variables[*]), or read the file once into string columns and parse those blobs in follow-up steps—see thejson-normalize-hop-config-layers.hplsample. -
Wide, sparse tables — It is possible in some cases to point the record path at a very high level (for example the document root) and flatten everything into one enormous row, but unrelated branches then become hundreds of columns with values only on a few of them. That is hard to query and heavy for memory. Prefer a narrow record path per entity type so each hop looks like a real table: mostly dense columns, one business meaning per row.
So chaining here is not a limitation of JSON compared to “doing it in one go”; it is the same design choice as picking one repeating array per logical table.
|
If you use Python pandas: The same pattern exists there— |
Performance, memory, and wide tables
Flattening is row-oriented and builds a wide field set from deep or branchy JSON:
-
Wide output — Many distinct paths (especially long field names or deep nesting) mean many columns and larger in-memory row batches. Very large config files with hundreds of top-level branches can create very wide rows if you flatten the whole document in one row.
-
Large files — Reading big JSON documents is not streaming per record at the JsonPath layer; the engine must materialize matching structures. Prefer narrow
Record JsonPath(one list of business records) instead of normalizing an enormous root when possible. -
Arrays left as JSON text — Stringified array columns can be large strings; downstream steps (for example filters, calculators) pay the cost of parsing or copying that text.
There is no single safe “normalize everything” default for arbitrary JSON; choosing the right record path is the main lever for both correctness and performance.
Samples
Sample pipelines and data ship with the JSON transforms plugin under plugins/transforms/json/src/main/samples/:
-
transforms/json-normalize-orders.hplwithdata/json-normalize-orders.json— nestedordersarray. -
transforms/json-normalize-root-array.hplwithdata/json-normalize-events.json— root-level array. -
transforms/json-normalize-complex-transactions.hplwithdata/json-normalize-complex-transactions.json— larger file with many columns and rows. -
transforms/json-normalize-hop-config-layers.hplreads${HOP_CONFIG_FOLDER}/hop-config.json— wide row from the root object (arrays as JSON text), then parallel branches that normalizevariables, lifecycle environments, and project configurations from those strings. PointHOP_CONFIG_FOLDERat your real Hop config folder, or use the fixture underintegration-tests/json/resources/hop-config-layers-it/to try the shape offline.
Pipeline unit tests in integration-tests/json/ (0008–0011) exercise these scenarios in CI, including 0011-json-normalize-hop-config-layers.hpl for ${HOP_CONFIG_FOLDER}/hop-config.json with parallel branches.
Options
File tab
Same concepts as JSON Input: source from files / folder, URL, or a field from a previous transform (Source is from a previous transform). See JSON Input – File tab for details.
Content tab
In addition to the usual file and row-limit options (see JSON Input – Content tab), the Content tab adds:
| Option | Description |
|---|---|
Record JsonPath |
JsonPath that must evaluate to an array of records. Each element becomes one output row. Examples: |
Field separator |
Character(s) placed between path segments when flattening nested objects (default |
Max flatten depth |
Maximum object nesting depth to flatten. |
Array handling |
How to handle JSON arrays encountered while flattening: stringify (default), single element only, or error. |
Beyond max depth |
When max depth is reached: stringify, omit, or error. |
Ignore missing field paths |
If enabled, fields listed on the Fields tab that are missing on a given row are set to null instead of failing the row. |
Fields tab
The Fields tab lists output fields to extract from each flattened record (each element selected by Record JsonPath). The table has the following columns:
| Option | Description |
|---|---|
Name |
Name of the output field in the Hop stream. |
Path |
Flattened key for the value within each record, after nested objects are merged into dotted (or custom-separated) paths. This is not a JsonPath into the whole document—that is what Record JsonPath on the Content tab is for. Examples: |
Type |
Data type of the input field. |
Format |
An optional mask for converting the format of the original field. See Formatting numbers and dates. |
Length |
Length of the field. |
Precision |
Number of floating point digits for number-type fields. |
Currency |
Currency symbol ($ or €, for example). |
Decimal |
A decimal point can be a . (5,000.00 for example) or , (5.000,00 for example). |
Group |
A grouping can be a , (10,000.00 for example) or . (5.000,00 for example). |
Trim type |
The trim method to apply to a string. |
Repeat |
The corresponding value from the last row repeated if a row is empty. |
Select fields
Click Select fields in the Fields tab to open the Select Fields window. Select the checkbox next to each field that you want in the output. All fields chosen here are added to the table. You can search for a field name by entering it in the Search box.
Select fields from snippet
Click Select fields from snippet and paste JSON text—typically one representative object (one element of the array your Record JsonPath selects)—to populate the Name, Path, and Type columns in the Fields tab. This helps discover flattened paths after your Content-tab settings (separator, depth, array handling) are applied.
Dates and timestamps
For Hop types of Date and Timestamp, use the Format column to specify the incoming format. For example, for Date: yyyy-MM-dd. You can select a format from the dropdown or enter format text directly.
See Formatting numbers and dates.
Examples of Timestamp formats:
-
Format: yyyy-MM-dd’T’HH:mm:ss.SSSZ and Result: 2021-10-26T20:51:43.795+0000
-
Format: 2024-04-22T00:00:00.000Z and Result: 2024-04-22T00:00:00.000Z
Additional output fields tab
The Additional output fields tab contains the following options to add file metadata when the transform reads from files:
| Option | Description |
|---|---|
Short filename field |
Specify the field that contains the filename without path information but with an extension. |
Extension field |
Specify the field that contains the extension of the filename. |
Path field |
Specify the field that contains the path in operating system format. |
Size field |
Specify the field that contains the size of the data. |
Is hidden field |
Specify the field indicating if the file is hidden or not (Boolean). |
Last modification field |
Specify the field indicating the date of the last time the file was modified. |
Uri field |
Specify the field that contains the URI. |
Root uri field |
Specify the field that contains only the root part of the URI. |