4

The goal is to return all records where a certain key is missing from a JSON data type. Just to make it obvious, I'm trying to query the JSON structure for anything where faultyField returns null among the following table data:

 id::SERIAL |       data::JSON
------------+-------------------
          1 | {"key" : "val"}
          2 | {"key1" : "val2"}

Any of the following two statements:

SELECT * FROM test WHERE data->>'faultyField' = null;
SELECT * FROM test WHERE (data->>'faultyField')::text = 'null';

Should return all values (according to two SO posts I found at work)? But it doesn't for some reason. These two just return empty results.

I'm no wizard with PostgreSQL so I've tried everything in between these statements below just to see if they work at all. Sadly they doesn't.

SELECT * FROM test WHERE (SELECT json_object_keys(data) FROM test)='key';
SELECT * FROM test WHERE 'key' in json_object_keys(data);
SELECT * FROM test WHERE 'key' := json_object_keys(data);
SELECT * FROM test WHERE 'key' ANY (json_object_keys(data));

Is there a way to return records where a key is missing from the JSON string?

2 Answers 2

7

Do not use = with null. Try:

select *
from test
where data->>'faultyField' is null;

From the documentation:

Do not write expression = NULL because NULL is not "equal to" NULL. (The null value represents an unknown value, and it is not known whether two unknown values are equal.)

Sign up to request clarification or add additional context in comments.

4 Comments

I guess the op is trying to check if a key exists rather than test its value. In this case data->>'faultyField' is null will return rows even faultyField key exists and has a null value. But I can be wrong.
Well, you're wrong. data->>'faultyField' is null is true if and only if the key is missing.
Are you sure? CREATE TEMP TABLE test AS SELECT 1 AS id, '{"key" : null}'::JSONB AS data; SELECT * FROM test WHERE data->>'key' IS NULL;. This test case returns the row as I expected. Tested on 9.5.6.
Works perfectly from what I can tell :)
7

EDIT

I heavily recommend you to use JSONB instead of JSON. It is a more powerful type that allows indexing and has additional operators such I demonstrated below.


If you want to test if a key don't exists in the top-level of jsonb field use ? operator:

CREATE TEMP TABLE test AS VALUES 
    (1, '{"key" : "val"}'::JSONB),
    (2, '{"key2" : "val2"}'::JSONB);

SELECT * FROM test WHERE NOT column2 ? 'key3';

Using data->>'faultyField' will attempt to get the value of this key rather than test if the key exists. This isn't what you're looking for because it will return rows even faultyField key exists and has a null value.

6 Comments

No operator matches the given name and argument type(s). You might need to add explicit type casts. on the ? - why is this?
The ? operator exists for JSONB type since 9.4. What's your PostgreSQL version? More info on docs.
I'm rocking v9.6.1 currently. JSONB is for bytes data tho?
No. JSONB stores json data in decomposed binary format. There are several advantages in comparison with simple JSON type, which is stored as a text, e.g: support for indexing. In general you might prefer to use JSONB instead of JSON.
Well, to avoid operator error you should cast your column to JSONB. Something like: SELECT * FROM test WHERE NOT data::JSONB ? 'key3';
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.