AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

A partial JSON update must distinguish deletion from no change

DuckDB’s JSON reconciliation preview exposes a contract question: whether an absent field, null value or deletion request should change stored state.

Citiți articolul în română

A partial JSON update needs a clear account of what its missing information means. A field that is absent, a request to delete a stored value and a value the receiver should ignore are different instructions. If the update format makes them indistinguishable, choosing a faster merge function cannot recover the sender’s intention.

The useful design decision comes before the function name: define which states the sender can express and what the receiver should do with each. Looking back from November 2026, DuckDB’s August reconciliation discussion provides a concrete reason to make that decision explicit. Two plausible merge operations can treat the same null very differently without either operation being internally inconsistent.

Read the preview as a preview

The August 18 guest post by Mustafa Khan of Atlan described upcoming JSON functions available in DuckDB 2.0-dev at the time. It contrasted json_merge_patch, where null deletes a key under RFC 7396 semantics, with proposed json_deep_merge behavior that skips null. These are different update contracts. The guest attribution matters: this is an account of Atlan’s reconciliation use case, not an AL+ implementation report.

The August 17 version preview supplies release context. Its current page includes an October 21 release update and warns that details changed. That later addition does not turn the August development functions into an August stable delivery. This article examines the semantic choice presented then; it does not certify the behavior of a currently installed API.

Absence is useful information

Imagine an illustrative customer record with a stored contact number. An update that changes only the display name leaves the contact number absent. A reasonable partial-update contract can interpret that absence as leaving the number unchanged. Sending the whole record instead would be a different contract, because omission could then have a different meaning.

Now suppose the sender includes the contact-number field with null. That might mean the person asked to remove it. It might also mean an upstream system did not provide a number in this event. The JSON representation alone cannot tell the receiver which intention applies. A domain agreement must supply the meaning before reconciliation can safely choose between preserving and erasing the stored value.

The two operations in the guest post make that distinction concrete. Deletion semantics serve a sender that can deliberately remove a key. Skip-on-null semantics serve a sender whose null should not overwrite known information. Neither choice can represent both meanings through the same field and value without additional information. The limit comes from the message’s expressive power, not from a lack of recursive merging.

Follow the meaning through the pipeline

A pipeline can lose that distinction before the final merge. If an intermediate transformation fills every absent field with null, the receiver can no longer tell which fields the original event omitted. Even a correctly implemented merge operation will then apply the contract to a message whose meaning has already changed. Reviewing the final SQL alone would miss the earlier loss.

For that reason, it helps to document a field’s journey from producer to stored state. Identify which component chooses the update meaning, which transformations preserve omission and where a deletion request becomes irreversible information loss. This is design advice, not a prescribed database implementation. The point is to make the semantic boundary visible enough for the people responsible for each side to agree on it.

The same reasoning applies when events arrive from more than one producer. A null from one source need not carry the same intention as a null from another. Normalizing their shape does not establish a shared contract. If sources disagree, the integration needs an explicit mapping or separate operations. Otherwise the same merge rule can be faithful to one producer and destructive to another.

Explicit operations may be the better choice

The strongest counterargument is that a merge-based contract becomes too implicit for a complex domain. An operation envelope can state that a field is to be set, removed or left alone. That representation can be more verbose, but the extra information may be exactly what the domain needs. It avoids making every reader infer an action from the presence of null.

An envelope also creates responsibilities of its own. The receiver has to validate which operations make sense and what happens when the target field is already absent. The teams still need an agreement about repeated updates and conflicting intentions. Explicit operations make those questions easier to name; they do not decide them automatically. A small integration with one clear null convention may reasonably prefer a simpler merge contract.

The choice should therefore follow the ambiguity you actually have. If every sender agrees that null means delete and that meaning survives every transformation, deletion semantics can be clear. If null consistently means unavailable information, skipping it may be appropriate. When both intentions are necessary, preserving both requires additional representation. Quietly selecting one interpretation would discard a real part of the domain.

Performance follows a valid contract

The guest post also presented a synthetic benchmark from Atlan. Such a comparison can motivate investigation, but it cannot establish representative market performance or the cost of a different integration. This article reports no AL+ measurement. More fundamentally, a fast operation that applies the wrong update meaning is still the wrong operation for that contract.

In custom software development, settle the update vocabulary with the people who produce and consume the data before choosing the primitive. Preserve omission where it matters, give deliberate deletion an unambiguous expression and keep unavailable information from becoming an accidental erase instruction. Once those meanings are clear, a merge function can implement the agreement instead of silently inventing it.