The JSON_EXISTS() function in PostgreSQL 17 provides a powerful way to check for the existence of values within JSON data using SQL/JSON path expressions. This function is particularly useful for validating JSON structure and implementing conditional logic based on the presence of specific JSON elements.
Use JSON_EXISTS() when you need to:
- Validate the presence of specific
JSONpaths - Implement conditional logic based on
JSONcontent - Filter
JSONdata based on complex conditions - Verify
JSONstructure before processing
Try it on Neon!
Neon is Serverless Postgres built for the cloud. Explore Postgres features and functions in our user-friendly SQL editor. Sign up for a free account to get started.
Function signature
The JSON_EXISTS() function uses the following syntax:
JSON_EXISTS(
context_item, -- JSON/JSONB input
path_expression -- SQL/JSON path expression
[ PASSING { value AS varname } [, ...] ]
[{ TRUE | FALSE | UNKNOWN | ERROR } ON ERROR ]
) → booleanParameters:
context_item:JSONorJSONBinput to evaluatepath_expression:SQL/JSONpath expression to checkPASSING: Optional clause to pass variables for use in the path expressionON ERROR: Controls behavior when path evaluation fails (defaults toFALSE)
Example usage
Let's explore various ways to use the JSON_EXISTS() function with different scenarios and options.
Basic existence checks
-- Check if a simple key exists
SELECT JSON_EXISTS('{"name": "Alice", "age": 30}', '$.name');# | json_exists
--------------
1 | t-- Check for a nested key
SELECT JSON_EXISTS(
'{"user": {"details": {"email": "alice@example.com"}}}',
'$.user.details.email'
);# | json_exists
--------------
1 | tArray operations
-- Check if array contains any elements
SELECT JSON_EXISTS('{"numbers": [1,2,3,4,5]}', '$.numbers[*]');# | json_exists
--------------
1 | t-- Check for specific array element
SELECT JSON_EXISTS('{"tags": ["postgres", "json", "database"]}', '$.tags[3]');# | json_exists
--------------
1 | fConditional checks
-- Check for values meeting a condition
SELECT JSON_EXISTS(
'{"scores": [85, 92, 78, 95]}',
'$.scores[*] ? (@ > 90)'
);# | json_exists
--------------
1 | tUsing PASSING clause
-- Check using a variable
SELECT JSON_EXISTS(
'{"temperature": 25}',
'strict $.temperature ? (@ > $threshold)'
PASSING 30 AS threshold
);# | json_exists
--------------
1 | fError handling
-- Default behavior (returns FALSE)
SELECT JSON_EXISTS(
'{"data": [1,2,3]}',
'strict $.data[5]'
);# | json_exists
--------------
1 | f-- Using ERROR ON ERROR
SELECT JSON_EXISTS(
'{"data": [1,2,3]}',
'strict $.data[5]'
ERROR ON ERROR
);ERROR: jsonpath array subscript is out of bounds (SQLSTATE 22033)-- Using UNKNOWN ON ERROR
SELECT JSON_EXISTS(
'{"data": [1,2,3]}',
'strict $.data[5]'
UNKNOWN ON ERROR
);# | json_exists
--------------
1 |Practical applications
Data validation
-- Validate required fields before insertion
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
data JSONB NOT NULL,
CONSTRAINT valid_profile CHECK (
JSON_EXISTS(data, '$.email') AND
JSON_EXISTS(data, '$.username')
)
);
-- This insert will succeed
INSERT INTO user_profiles (data) VALUES (
'{"email": "user@example.com", "username": "user123"}'::jsonb
);
-- This insert will fail
INSERT INTO user_profiles (data) VALUES (
'{"username": "user123"}'::jsonb
);ERROR: new row for relation "user_profiles" violates check constraint "valid_profile" (SQLSTATE 23514)Conditional queries
-- Filter records based on JSON content
SELECT *
FROM user_profiles
WHERE JSON_EXISTS(
data,
'$.preferences.notifications ? (@ == true)'
);Best practices
-
Error handling:
- Use appropriate
ON ERRORclauses based on your requirements - Consider
UNKNOWN ON ERRORfor nullable conditions - Use
ERROR ON ERRORwhen validation is critical
- Use appropriate
-
Performance optimization:
- Create GIN indexes on
JSONBcolumns for better performance - Use strict mode when path is guaranteed to exist
- Combine with other
JSONfunctions for complex operations
- Create GIN indexes on
-
Path expressions:
- Use lax mode (default) for optional paths
- Leverage path variables with
PASSINGclause for dynamic checks