diff --git a/docs/data/sql_functions.yml b/docs/data/sql_functions.yml index 1535c4d375f0e..8d496e6af9794 100644 --- a/docs/data/sql_functions.yml +++ b/docs/data/sql_functions.yml @@ -1685,6 +1685,17 @@ bitmapagg: `bitmap BITMAP` Returns a `BIGINT`. + - sql: JSON_LENGTH(json_doc[, path]) + table: jsonLength(jsonObject[, path]) + description: | + Returns the number of elements in a JSON document, or the length of the value at the specified path if one is provided. + Returns NULL if the argument is NULL or the path does not locate a value. + + The length is determined as follows: + a scalar value (number, string, boolean, or null) has length 1; + an array has a length equal to the number of its elements; + and an object has a length equal to the number of its key-value pairs. + Nested arrays and objects each count as a single element and their contents are not included in the count. catalog: - sql: CURRENT_DATABASE() diff --git a/flink-python/docs/reference/pyflink.table/expressions.rst b/flink-python/docs/reference/pyflink.table/expressions.rst index e2aeb34f41107..afa67f2a8a48e 100644 --- a/flink-python/docs/reference/pyflink.table/expressions.rst +++ b/flink-python/docs/reference/pyflink.table/expressions.rst @@ -319,13 +319,13 @@ JSON functions .. autosummary:: :toctree: api/ - Expression.is_json Expression.json_exists Expression.json_value Expression.json_query Expression.json_quote Expression.json_unquote + Expression.json_length value modification functions ---------------------------- diff --git a/flink-python/pyflink/table/expression.py b/flink-python/pyflink/table/expression.py index 82c49f2edc63d..f764739fdcc8d 100644 --- a/flink-python/pyflink/table/expression.py +++ b/flink-python/pyflink/table/expression.py @@ -2257,6 +2257,23 @@ def json_unquote(self) -> 'Expression': """ return _unary_op("jsonUnquote")(self) + def json_length(self, path = None) -> 'Expression': + """ + Return the length of a JSON value, or of the value at `path` if given. + + - Scalars have length 1. + - Arrays have length equal to their number of elements. + - Objects have length equal to their number of keys. + - Nested arrays/objects are not counted recursively. + - Returns None if the value is None. + """ + + + return _unary_op("jsonLength")(self) if path is None else _binary_op("jsonLength")(self, path) + + + + # ---------------------------- value modification functions ----------------------------- def object_update(self, *kv) -> "Expression": diff --git a/flink-table/flink-table-api-java/src/main/java/org/apache/flink/table/api/internal/BaseExpressions.java b/flink-table/flink-table-api-java/src/main/java/org/apache/flink/table/api/internal/BaseExpressions.java index 074224ae696fd..81e84bab81579 100644 --- a/flink-table/flink-table-api-java/src/main/java/org/apache/flink/table/api/internal/BaseExpressions.java +++ b/flink-table/flink-table-api-java/src/main/java/org/apache/flink/table/api/internal/BaseExpressions.java @@ -140,6 +140,7 @@ import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.IS_TRUE; import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.IS_VALID_UTF8; import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_EXISTS; +import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_LENGTH; import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_QUERY; import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_QUOTE; import static org.apache.flink.table.functions.BuiltInFunctionDefinitions.JSON_UNQUOTE; @@ -2523,6 +2524,27 @@ public OutType jsonQuery(String path, JsonQueryWrapper wrappingBehavior) { return jsonQuery( path, wrappingBehavior, JsonQueryOnEmptyOrError.NULL, JsonQueryOnEmptyOrError.NULL); } + /** + * Returns the number of elements contained in a JSON value, optionally at a given path. + * + *
Counting works differently depending on the JSON type: objects report how many + * key-value pairs they contain, arrays report how many entries they hold, and any scalar + * value (such as a number, string, or boolean) is treated as a single element and reports 1. + * Only the top level is measured — elements that are themselves arrays or objects contribute + * 1 to the count regardless of what they contain. + * + *
When a path is provided, the count applies to the value found at that path rather than
+ * the document as a whole. Returns NULL if any argument is NULL{@code} or the path does not
+ * match a value.
+ */
+
+ public OutType jsonLength() {
+ return toApiSpecificExpression(unresolvedCall(JSON_LENGTH, toExpr()));
+ }
+
+ public OutType jsonLength(String path) {
+ return toApiSpecificExpression(unresolvedCall(JSON_LENGTH, toExpr(), valueLiteral(path)));
+ }
/**
* Extracts JSON values from a JSON string.
diff --git a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/functions/BuiltInFunctionDefinitions.java b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/functions/BuiltInFunctionDefinitions.java
index 0828f2bb8b4e9..d7511fe36e35a 100644
--- a/flink-table/flink-table-common/src/main/java/org/apache/flink/table/functions/BuiltInFunctionDefinitions.java
+++ b/flink-table/flink-table-common/src/main/java/org/apache/flink/table/functions/BuiltInFunctionDefinitions.java
@@ -3081,6 +3081,23 @@ ANY, and(logical(LogicalTypeRoot.BOOLEAN), LITERAL)
.runtimeProvided()
.build();
+ public static final BuiltInFunctionDefinition JSON_LENGTH =
+ BuiltInFunctionDefinition.newBuilder()
+ .name("JSON_LENGTH")
+ .kind(SCALAR)
+ .inputTypeStrategy(
+ or(
+ sequence(logical(LogicalTypeFamily.CHARACTER_STRING)),
+ sequence(
+ logical(LogicalTypeFamily.CHARACTER_STRING),
+ and(
+ logical(LogicalTypeFamily.CHARACTER_STRING),
+ LITERAL))))
+ .outputTypeStrategy(nullableIfArgs(explicit(DataTypes.INT())))
+ .runtimeClass(
+ "org.apache.flink.table.runtime.functions.scalar.JsonLengthFunction")
+ .build();
+ // I need to complete this
// --------------------------------------------------------------------------------------------
// Variant functions
// --------------------------------------------------------------------------------------------
diff --git a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
index 89a0448e95eef..47ac3f928be68 100644
--- a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
+++ b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/JsonFunctionsITCase.java
@@ -84,6 +84,7 @@ Stream