Expressions for manipulating JSON values.
JSONValue
A json-like collection with dynamic keys and values.
Examples
Construct a table with a JSON column
import json, ibis
ibis.options.interactive = True
rows = [{"js": json.dumps({"a": [i, 1]})} for i in range(2)]
t = ibis.memtable(rows, schema=ibis.schema(dict(js="json")))
t
┏━━━━━━━━━━━━━━┓
┃ js ┃
┡━━━━━━━━━━━━━━┩
│ json │
├──────────────┤
│ {'a': [...]} │
│ {'a': [...]} │
└──────────────┘
Extract the "a" field
┏━━━━━━━━━━━━━━━━━━━━━━┓
┃ JSONGetItem(js, 'a') ┃
┡━━━━━━━━━━━━━━━━━━━━━━┩
│ json │
├──────────────────────┤
│ [0, 1] │
│ [1, 1] │
└──────────────────────┘
Extract the first element of the JSON array at "a"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ JSONGetItem(JSONGetItem(js, 'a'), 0) ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ json │
├──────────────────────────────────────┤
│ 0 │
│ 1 │
└──────────────────────────────────────┘
Extract a non-existent field
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ JSONGetItem(JSONGetItem(js, 'a'), 'foo') ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ json │
├──────────────────────────────────────────┤
│ NULL │
│ NULL │
└──────────────────────────────────────────┘
Try to extract an array element, returns NULL
┏━━━━━━━━━━━━━━━━━━━━━┓
┃ JSONGetItem(js, 20) ┃
┡━━━━━━━━━━━━━━━━━━━━━┩
│ json │
├─────────────────────┤
│ NULL │
│ NULL │
└─────────────────────┘
Attributes
| array |
Cast JSON to an array of JSON. |
| bool |
Unwrap a JSON value into a backend-native boolean. |
| float |
Unwrap a JSON value into a backend-native float. |
| int |
Unwrap a JSON value into a backend-native int. |
| map |
Cast JSON to a map of string to JSON. |
| str |
Unwrap a JSON string into a backend-native string. |
Methods
| unwrap_as |
Unwrap JSON into a specific data type. |
unwrap_as
Unwrap JSON into a specific data type.
Returns
|
Value |
An Ibis expression of a more specific type than JSON |
Examples
import ibis
ibis.options.interactive = True
data = {
"jstring": ['"a"', '""', None, "null"],
"jbool": ["true", "false", "null", None],
"jint": ["1", "null", None, "2"],
"jfloat": ["42.42", None, "null", "37.37"],
"jmap": ['{"a": 1}', "null", None, "{}"],
"jarray": ["[]", "null", None, '[{},"1",2]'],
}
t = ibis.memtable(data, schema=dict.fromkeys(data.keys(), "json"))
t
┏━━━━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
┃ jstring ┃ jbool ┃ jint ┃ jfloat ┃ jmap ┃ jarray ┃
┡━━━━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│ json │ json │ json │ json │ json │ json │
├─────────┼───────┼──────┼────────┼──────────┼──────────────────────┤
│ 'a' │ True │ 1 │ 42.42 │ {'a': 1} │ [] │
│ '' │ False │ None │ NULL │ None │ None │
│ NULL │ None │ NULL │ None │ NULL │ NULL │
│ None │ NULL │ 2 │ 37.37 │ {} │ [{...}, '1', ... +1] │
└─────────┴───────┴──────┴────────┴──────────┴──────────────────────┘
t.select(unwrapped=t.jstring.unwrap_as(str), original=t.jstring)
┏━━━━━━━━━━━┳━━━━━━━━━━┓
┃ unwrapped ┃ original ┃
┡━━━━━━━━━━━╇━━━━━━━━━━┩
│ string │ json │
├───────────┼──────────┤
│ a │ 'a' │
│ ~ │ '' │
│ NULL │ NULL │
│ NULL │ None │
└───────────┴──────────┘
t.select(unwrapped=t.jbool.unwrap_as("bool"), original=t.jbool)
┏━━━━━━━━━━━┳━━━━━━━━━━┓
┃ unwrapped ┃ original ┃
┡━━━━━━━━━━━╇━━━━━━━━━━┩
│ boolean │ json │
├───────────┼──────────┤
│ True │ True │
│ False │ False │
│ NULL │ None │
│ NULL │ NULL │
└───────────┴──────────┘
t.select(
unwrapped_int64=t.jint.unwrap_as("int64"),
unwrapped_int32=t.jint.unwrap_as("int32"),
original=t.jint,
)
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ unwrapped_int64 ┃ unwrapped_int32 ┃ original ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ int64 │ int32 │ json │
├─────────────────┼─────────────────┼──────────┤
│ 1 │ 1 │ 1 │
│ NULL │ NULL │ None │
│ NULL │ NULL │ NULL │
│ 2 │ 2 │ 2 │
└─────────────────┴─────────────────┴──────────┘
You can cast to a more specific type than the types available in standards-compliant JSON.
Here’s an example of casting JSON numbers to float32:
t.select(unwrapped=t.jfloat.unwrap_as("float32"), original=t.jfloat)
┏━━━━━━━━━━━┳━━━━━━━━━━┓
┃ unwrapped ┃ original ┃
┡━━━━━━━━━━━╇━━━━━━━━━━┩
│ float32 │ json │
├───────────┼──────────┤
│ 42.419998 │ 42.42 │
│ NULL │ NULL │
│ NULL │ None │
│ 37.369999 │ 37.37 │
└───────────┴──────────┘
You can cast JSON objects to a more specific map type:
t.select(unwrapped=t.jmap.unwrap_as("map<string, int>"), original=t.jmap)
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ unwrapped ┃ original ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ map<string, int64> │ json │
├────────────────────┼──────────┤
│ {'a': 1} │ {'a': 1} │
│ NULL │ None │
│ NULL │ NULL │
│ {} │ {} │
└────────────────────┴──────────┘
You can cast JSON arrays to an array type as well. In this case the array values don’t have a single element type so we cast to array<json>.
t.select(unwrapped=t.jarray.unwrap_as("array<json>"), original=t.jarray)
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
┃ unwrapped ┃ original ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│ array<json> │ json │
├───────────────────────┼──────────────────────┤
│ [] │ [] │
│ NULL │ None │
│ NULL │ NULL │
│ ['{}', '"1"', ... +1] │ [{...}, '1', ... +1] │
└───────────────────────┴──────────────────────┘
Back to top