Before erasing a phone number, check what was sent
An imagined contact form loses a phone number after a name edit. JSONB values and partial-update instructions need different interpretations.

Only the name changed
Imagine a contact-editing screen. There is a typo in the name, so you fix one letter. You leave the phone number alone. After saving, the name is correct and the number has disappeared.
‘Did you mean to erase the number too?’ would be a strange question to receive. You came to fix the name.
Suppose this screen uses partial updates, sending only changed fields. The request contains the name and omits the phone field. If the server fills omitted fields with empty values before saving, it can erase a number nobody edited.
A missing field, an explicit null and an empty string can all look like an empty box on a screen. They can still ask the application to do different things.
VisuaLeaf’s JSONB guide describes changing individual values without replacing the whole document. Reading it made me think about a decision made earlier: choosing what to erase or preserve before the storage function even runs.
Where did the absence come from?
PostgreSQL’s documentation says extracting a nonexistent JSON key or path returns SQL NULL. That needs to be distinguished from a JSON null actually present in a JSONB object.
Checking key existence alongside functions such as jsonb_typeof can help. The text ‘null’ returned for a JSON null’s type is also distinct from SQL NULL.
Look only at the extracted phone value in this example, conclude ‘there is no value,’ and it is easy to skip a question. Was that field included in the request at all?
For this hypothetical partial-update app, I would choose to preserve the existing number when the phone field is omitted. Check presence before supplying a default value.
An intentional deletion should arrive as an intentional instruction. The client and server need to agree on how to express it.
JSON Merge Patch provides one such contract. For the object patches defined in RFC 7396, omitted members remain unchanged and members sent as null are removed.
If this app adopts that format, a request omitting phone and one containing ‘phone: null’ request different edits. Naming an endpoint PATCH does not make every API follow those rules.
A stored value and an instruction
There is another possible mix-up. ‘Phone: null’ stored in JSONB describes a data state. In a JSON Merge Patch request, it instructs the recipient to remove that member.
A database function that stores a null does not automatically implement this contract. The API must translate the request into the intended operation.
What if the product needs to store a JSON null as an explicit value? A format using null for removal cannot directly express setting that value in the same way. A different update format or explicit operation may fit that requirement better.
I would keep empty strings out of the same bucket too. This imagined contact app needs to decide whether an empty phone value is allowed or rejected. Then check what the form actually sends when someone clears the box.
To examine this hypothetical app, I would save three cases: a name-only edit, an explicit number deletion and a cleared phone box. Check the resulting name and number, and inspect whether an intermediate layer turns an omitted field into null.
If the server’s chosen update format differs from what the screen sends, changing one storage function may leave the problem waiting to happen again.
A contact without a number does not tell its whole story. The number might never have been supplied, or it might have been deliberately removed. In an update request, leaving it out can carry another meaning: leave it alone.
One empty box is doing a surprising amount of talking.
The person fixing a typo does not see any of this. They just expect the number to remain when the screen opens again.
Before erasing it, I would like to find the instruction that asked for that.

