ApsaraDB for SelectDB supports complex data types such as ARRAY, MAP, STRUCT, JSON, and VARIANT. These data types are ideal for storing and querying nested and semi-structured data. This topic describes the use cases, table creation methods, and common query functions for each complex data type.
Overview
In real-world business scenarios, data often contains semi-structured information, such as lists of tags, attribute key-value pairs, or nested objects. Traditional relational columns like VARCHAR or INT cannot efficiently represent this data. ApsaraDB for SelectDB provides the following complex data types to address this need:
Data type | Description | Use cases |
ARRAY | An ordered collection of elements of the same type. | Tag lists, multi-value attributes, and sequences of scores. |
MAP | A collection of key-value pairs, where keys and values have specified types. | Extended attributes, configuration items, and dynamic fields. |
STRUCT | A collection of named fields, each with a specific data type. | Address information, coordinates, and nested entities. |
JSON | JSON data stored in a binary format. | Semi-structured data with a flexible schema and log events. |
VARIANT | A semi-structured data type that automatically infers types and uses columnar storage. | Scenarios with dynamically changing fields, such as log analysis and user profiling. |
ARRAY type
The ARRAY type stores an ordered collection of elements of the same type. The declaration syntax is ARRAY<element_type>. Nested arrays, such as ARRAY<ARRAY<INT>>, are also supported.
Create table example
CREATE TABLE user_tags (
user_id BIGINT,
tags ARRAY<VARCHAR(50)>,
scores ARRAY<INT>
)
DUPLICATE KEY(user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");Insert data
INSERT INTO user_tags VALUES
(1, ['sports', 'music', 'travel'], [90, 85, 78]),
(2, ['tech', 'gaming'], [95, 88]),
(3, ['cooking', 'reading', 'sports', 'photography'], [70, 92, 80, 65]);Common query functions
Function | Description | Example |
| Accesses an element by its index (0-based). |
|
| Returns the number of elements in the array. |
|
| Checks if the array contains a specified element. |
|
| Returns a sorted array. |
|
| Returns an array with duplicate elements removed. |
|
| Joins array elements into a string. |
|
For more ARRAY functions, see the Apache Doris Array Functions documentation.
Flattening an array
Use the EXPLODE() function with LATERAL VIEW to expand each array element into a separate row.
SELECT user_id, tag
FROM user_tags
LATERAL VIEW EXPLODE(tags) tmp AS tag;MAP type
The MAP type stores a collection of key-value pairs. The declaration syntax is MAP<key_type, value_type>. The key must be a primitive type, while the value can be a nested complex data type.
Create table example
CREATE TABLE product_attrs (
product_id BIGINT,
attributes MAP<VARCHAR(50), VARCHAR(200)>
)
DUPLICATE KEY(product_id)
DISTRIBUTED BY HASH(product_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");Insert data
INSERT INTO product_attrs VALUES
(1001, {'color': 'red', 'size': 'XL', 'material': 'cotton'}),
(1002, {'color': 'blue', 'weight': '500g'}),
(1003, {'brand': 'Acme', 'origin': 'China', 'warranty': '2 years'});Common query functions
Function | Description | Example |
| Retrieves a value by its key. |
|
| Returns the number of key-value pairs. |
|
| Returns an array of all keys. |
|
| Returns an array of all values. |
|
| Checks if the map contains a specified key. |
|
For more MAP functions, see the Apache Doris Map Functions documentation.
Flattening a map
SELECT product_id, key, value
FROM product_attrs
LATERAL VIEW EXPLODE_MAP(attributes) tmp AS key, value;STRUCT type
The STRUCT type consists of a set of named fields, each of which can have a different data type. The declaration syntax is STRUCT<field1:type1, field2:type2, ...>.
Create table example
CREATE TABLE orders (
order_id BIGINT,
address STRUCT<city:VARCHAR(50), street:VARCHAR(200), zipcode:VARCHAR(10)>
)
DUPLICATE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");Insert data
INSERT INTO orders VALUES
(1, NAMED_STRUCT('city', 'Beijing', 'street', 'Zhongguancun Road 1', 'zipcode', '100080')),
(2, NAMED_STRUCT('city', 'Shanghai', 'street', 'Nanjing West Road 100', 'zipcode', '200041'));Query methods
Use dot notation (.) to access fields within a struct:
-- Access fields of a struct
SELECT order_id, address.city, address.zipcode FROM orders;
-- Use a struct field in a WHERE clause
SELECT * FROM orders WHERE address.city = 'Beijing';JSON type
The JSON type stores JSON data in a binary format and is suitable for semi-structured data scenarios with a flexible schema. Compared to storing a JSON string as VARCHAR, the JSON type provides better query performance because it avoids repeated parsing.
Create table example
CREATE TABLE event_logs (
event_id BIGINT,
event_time DATETIME,
payload JSON
)
DUPLICATE KEY(event_id)
DISTRIBUTED BY HASH(event_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");Insert data
INSERT INTO event_logs VALUES
(1, '2024-01-15 10:30:00', '{"action": "login", "device": "mobile", "os": "iOS", "version": "17.2"}'),
(2, '2024-01-15 10:31:00', '{"action": "purchase", "amount": 99.9, "items": ["book", "pen"], "coupon": null}'),
(3, '2024-01-15 10:32:00', '{"action": "logout", "duration_sec": 300}');Common query functions
Function | Description | Example |
| Extracts a value using a JSONPath expression. |
|
| Extracts a JSON value and returns it as a string. |
|
| Extracts a JSON value and returns it as an integer. |
|
| Extracts a JSON value and returns it as a double. |
|
| Checks if a specified path exists. |
|
| Returns the type of a JSON value. |
|
For more JSON functions, see the Apache Doris JSON Functions documentation.
Usage notes
For frequently queried JSON fields, consider extracting them into separate columns or using the VARIANT type for better query performance.
The JSON type cannot be used as a key column or for partitioning and bucketing.
The maximum size for a single JSON field is 1 GB.
VARIANT type
VARIANT is a semi-structured data type provided by ApsaraDB for SelectDB that automatically infers the specific data type and stores it in columnar storage. Compared to the JSON type, VARIANT offers superior query performance and is ideal for scenarios that require high-performance analysis on data with variable fields.
Create table example
CREATE TABLE user_events (
event_id BIGINT,
event_time DATETIME,
event_data VARIANT
)
DUPLICATE KEY(event_id)
DISTRIBUTED BY HASH(event_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");Insert data
The VARIANT type accepts JSON-formatted strings. The system automatically infers the schema and stores the data in columnar storage.
INSERT INTO user_events VALUES
(1, '2024-01-15 10:00:00', '{"uid": 1001, "action": "click", "page": "/home", "duration": 5.2}'),
(2, '2024-01-15 10:01:00', '{"uid": 1002, "action": "scroll", "page": "/products", "items_viewed": 12}'),
(3, '2024-01-15 10:02:00', '{"uid": 1001, "action": "purchase", "amount": 299.0, "payment": "alipay"}');Query methods
Access VARIANT fields using dot or bracket notation. You can also use CAST to perform type conversions:
-- Directly access fields (returns a VARIANT type)
SELECT event_data['action'], event_data['page'] FROM user_events;
-- Convert types using CAST
SELECT
CAST(event_data['uid'] AS BIGINT) AS uid,
CAST(event_data['action'] AS VARCHAR) AS action,
CAST(event_data['amount'] AS DOUBLE) AS amount
FROM user_events
WHERE CAST(event_data['action'] AS VARCHAR) = 'purchase';VARIANT vs. JSON
Dimension | VARIANT | JSON |
Storage method | columnar storage with automatic type inference | binary JSON format |
Query performance | High (columnar storage and vectorized execution) | Medium (requires runtime parsing) |
Schema flexibility | Automatically adapts without a predefined schema | Completely flexible |
Recommended use cases | Scenarios requiring high-performance analysis, such as log analysis and user behavior analysis | Scenarios with extremely high write frequency and highly variable fields |
Limitations
ARRAY, MAP, STRUCT, JSON, and VARIANT types cannot be used as a table's key column (such as columns in a DUPLICATE KEY, UNIQUE KEY, or AGGREGATE KEY).
Complex data types cannot be used as bucketing columns in a
DISTRIBUTED BYclause.The ARRAY and MAP types can be nested up to 9 levels deep.
In an AGGREGATE KEY table, the only supported aggregate functions for complex-type columns are
REPLACE_IF_NOT_NULLandNONE.