如何通过Python API正确向DuckDB的JSON类型插入数据?
我之前也纠结过这个问题,DuckDB的Python API文档里只讲了怎么读取JSON文件,却没明确说明怎么往JSON类型的字段里插入Python对象(比如嵌套字典、列表这类半结构化数据)。你提到的两种插入方式我都试过,表面上看都能正常运行,但实际用起来差异很大。
先看两种常见的写法:
- 方式1:直接传入Python对象,代码更简洁直观:
conn.execute("INSERT INTO test VALUES (?)", (obj,)) - 方式2:先用
json.dumps()将对象序列化为JSON字符串再传入:conn.execute("INSERT INTO test VALUES (?)", (json.dumps(obj),))
一开始我也倾向于用方式1,毕竟少了一步序列化,看起来更高效。但后来发现这种写法有个隐藏的坑:DuckDB会自动把Python的嵌套结构转换成STRUCT类型,而不是我们预期的JSON类型。
你用pytest做的测试案例正好戳中了这个问题的痛点:当插入像[{"a": 1}, {"b": 2}]这种元素结构不统一的列表时,方式1会直接抛出类型不匹配的错误:
duckdb.duckdb.TypeMismatchException: Mismatch Type Error: Type STRUCT(b INTEGER) does not match with STRUCT(a INTEGER). Cannot cast STRUCTs - element "b" in source struct was not found in target struct
这是因为STRUCT在DuckDB里是固定Schema的类型,当插入第一个元素{"a":1}时,DuckDB会自动推断出STRUCT的结构是{a: INTEGER},第二个元素{"b":2}的结构和它不匹配,自然就报错了。
而方式2就完全不会有这个问题,因为传入的是标准的JSON字符串,DuckDB会把它正确识别为JSON类型——JSON类型本来就是为了处理这种Schema不固定的半结构化数据设计的,不管元素结构是否统一都能正常存储。
那这种情况是Bug吗?其实不是,这是DuckDB的预期行为:它对Python的原生嵌套数据(字典、列表)默认会映射到对应的结构化类型(STRUCT、ARRAY),而不是JSON类型。JSON类型在DuckDB里是独立的类型,需要显式传入JSON格式的字符串才能触发对应的处理逻辑。
最终建议
虽然方式1看起来更简便,但强烈推荐使用方式2(预序列化后插入):
- 它能避免结构不匹配导致的插入错误,适配所有半结构化的JSON数据场景;
- 能确保数据被正确存储为JSON类型,后续查询、处理时不会出现类型混淆的问题;
- 这种用法在未来的DuckDB版本中也会更稳定可靠,不会因为内部类型映射逻辑的调整而出现问题。
备注:内容来源于stack exchange,提问作者Chris Mungall

