As far as I can tell duckdb does not currently support [*] in a json path; it seems to use a json library implementation from sqlite which does not support this functionality.
I created my own macro:
CREATE OR REPLACE MACRO json_array_extract_text(jsdata, jspath) AS (
WITH jsp AS (
SELECT x
FROM (SELECT STR_SPLIT(jspath, '[*]') AS x)
), arraylen AS (
SELECT
json_array_length(jsdata, x[1]) AS len
FROM jsp AS x
), jindex AS (
SELECT RANGE(CAST(x.len AS BIGINT)) as ix
FROM arraylen as x
), jindex_xpand AS (
SELECT UNNEST(j.ix) AS index
FROM jindex AS j
), paths AS (
SELECT x[1] || '[' || ix.index || ']' || x[2] AS path
FROM jindex_xpand AS ix
CROSS JOIN jsp AS x
ORDER BY ix.index
)
SELECT ARRAY_AGG(json_extract_string(jsdata, p.path)) AS array
FROM paths as p
);
It uses the json_array_length
function to determine how many indices to build and then builds the paths by replacing [*] which each index.
Would appreciate any clues in how to simplify this.
CREATE OR REPLACE TABLE example (j JSON);
INSERT INTO example VALUES
('{
"family": "anatidae",
"species": [
{"name": "duck", "animal": true},
{"name": "goose", "animal": true},
{"name": "rock", "animal": false}
]
}'
);
SELECT list_contains(json_array_extract_text(e.j, '$.species[*].name'), 'duck')
FROM example AS e;
output
list_contains(json_array_extract_text(e.j, '$.species[*].name'), 'duck')
0 True