MERGE_JSON will be available starting with the StarTree Cloud 0.17.0 release.
Contact StarTree support to confirm availability in your environment before enabling it. The configuration on
this page requires StarTree’s implementation and does not apply to an unmodified Apache Pinot deployment.MERGE_JSON combines an incoming JSON object with the stored object for the same primary key during ingestion.
Use it when events update individual attributes and should retain attributes omitted from later events.
Queries and JSON indexes see the resulting merged value.
Configure MERGE_JSON per column in a realtime partial-upsert table and choose one object-merge mode for the table:
Both modes replace arrays;
append does not concatenate them. This is an ingestion configuration, not a SQL
function. Use the same MERGE_JSON function name for both modes.
Example: update a customer profile
Suppose the storedattributes column contains:
append, the resulting column is:
override, the resulting column is:
account survives, tags is replaced, and contact remains a key with a null value.
Only append retains settings.theme.
Configure a table
Prerequisites
- Confirm with StarTree support that the feature is available on every server that can host the table.
- Start with a correctly configured realtime partial-upsert table: primary keys, stream
records partitioned by primary key, a comparison column, null handling, and appropriate routing and assignment.
The custom-merger settings below replace the recipe’s
partialUpsertStrategiesmap. - Include the primary key and comparison value in every update. Choose an ordering value that represents the intended update order for each key.
- Use a single-value
JSONcolumn for variable-shape JSON objects. Serialized JSON-objectSTRINGcolumns and nativeMAPvalues are also supported. MAP keys and values must remain compatible with the column’s complex schema.
Schema example
This schema defines the columns used below.attributes contains the object to merge; score demonstrates a
built-in numeric merge function on the same row.
Table configuration
Merge these sections into your existingprofile_events realtime table config. This is a fragment, not a
complete table definition: retain the stream, time-column, retention, tenant, routing, and partition-assignment
settings. Preserve existing metadataManagerClass and other metadataManagerConfigs entries.
attributes, adds each incoming score to the previous score, and uses
OVERWRITE for other non-key columns such as name. Primary-key and comparison columns are never merged.
With no previous value to merge, the incoming value becomes the initial value.
The example enables table-level null handling. Schema-level enableColumnBasedNullHandling is also supported;
when using it, keep the fields that can be omitted or null nullable rather than marking them notNull.
Do not also configure partialUpsertStrategies: it is mutually exclusive with partialUpsertMergerClass.
When migrating an existing table, move its column strategies into startree.merger.columns.<column> entries.
To select override, add this entry to upsertConfig.metadataManagerConfigs:
MERGE_JSON column in the table. It cannot be selected separately per column.
It does not change built-in strategies. Built-in OVERWRITE replaces an entire non-null column value;
JSON override still preserves absent top-level keys inside the column.
Configuration reference
Function names and modes ignore case and surrounding whitespace. Column names are trimmed; duplicate names
after trimming are rejected. Null, blank, or unknown functions/modes, primary-key or
comparison-column targets, and an empty function map fail merger construction.
Merge rules and invalid input
An incoming empty nested object such as
{"settings":{}} retains the previous nested keys in append mode,
and clears that nested object’s contents in override mode. Neither mode provides a key-deletion operator;
omitted top-level keys survive. Use whole-column replacement if that is the intended operation.
SQL null and JSON null differ. An absent or SQL-null incoming attributes column preserves its previous value
under MERGE_JSON. A JSON object such as {"contact":null} sets a key to null. The string "null" as the entire
serialized document is a non-object input. A built-in FORCE_OVERWRITE column can accept SQL null to clear the
whole column; that column then follows replacement semantics instead of JSON merging.
Object merging requires both serialized strings to parse as single JSON objects. Otherwise, the merger uses
the fallbacks below:
For example,
{"a":1} plus [2] keeps {"a":1}, while 42 plus {"a":2} becomes {"a":2}.
These are merge-stage fallbacks, not record-validation guarantees: decoding, transforms, and schema conversion
can reject or normalize data before it reaches the merger. A first record has no previous object to preserve.
Two native MAP values merge as maps. A mixed representation such as MAP plus string, or unsupported runtime
values such as numbers, keeps the incoming value. Use a consistent representation for each column.
The merger preserves numeric precision when parsing JSON strings; it does not preserve original whitespace or
key order, or restore precision already lost during decoding or conversion.
Ordering, recovery, and operations
MERGE_JSON follows Pinot’s existing partial-upsert ordering and previous-row selection. An older event excluded
by that ordering cannot contribute missing keys later. Preserve per-key ordering upstream; merge operations are
not generally commutative. Equal comparison values are not a deduplication mechanism: an accepted replay can
reapply functions such as INCREMENT.
Deletion, metadata expiry, retention, and reinsertion keep their existing Pinot behavior. Updates after deletion
start from the incoming fields rather than inheriting the deleted object’s attributes, subject to normal record
ordering. Once previous-key metadata expires, the next record also starts fresh. TTL applies to Pinot’s record
and metadata lifecycle, not to individual keys inside a JSON object. The plugin does not implement key deletion,
scripted updates, or the complete Elasticsearch Update API.
For rollout and configuration changes:
- Confirm availability with StarTree support and coordinate any required deployment update.
- For a new table, apply the configuration and verify construction succeeds. For an existing table, pause table consumption before changing merger settings, then coordinate the configuration update and server restart with StarTree support. Resume consumption only after all replicas have recreated their partition mergers with the same settings. A rolling mode change during consumption can produce different accumulated documents across replicas; a segment reload alone does not recreate the partition merger.
- Ingest two ordered updates for a test key and query the stored result. Check a retained key and a replaced key; if using a JSON index, also check that a predicate on the old value no longer matches.
- Coordinate rollback with StarTree support. Before using a deployment without this feature, remove
partialUpsertMergerClassand its merger-specific metadata settings, and configure the intended built-in upsert behavior. Already merged data is not undone.
attributes result should match the chosen mode in the customer-profile example. If the table has a
JSON index, test its predicates against the merged document too.
Settings are captured at construction. A mode change is not retroactive, and hot configuration migration is not
provided. Each partition owns its merger and failure state.
Malformed JSON and unsupported types produce rate-limited fallback warnings. A built-in function that throws
keeps the incoming value; after 100 consecutive exceptions for a column, that column switches to OVERWRITE
until its merger is recreated. A successful merge resets that exception streak but not the per-column warning
timer; a later failure can still have its warning suppressed within the 10-second interval. The documented JSON
fallbacks return normally and do not trigger this exception latch. Warnings are not a per-record error counter,
and this plugin does not export a dedicated degraded-merge metric.
Keys accumulate over time. For serialized JSON values, a successful object merge parses both strings and serializes
the result. Native MAP values instead incur map allocation and copying, including recursive merging in append
mode. Check representative document sizes, nesting, update rates, and ingestion lag before production adoption.
Troubleshooting
Related documentation
- Off-heap upserts: metadata storage, snapshot, preload, and TTL settings.
- Partial upserts: the base partial-upsert ingestion model and built-in strategies.
- JSON index: filter the merged JSON document efficiently.

