SQLite json_each 与 json_tree:看见了数组,为什么还没有拿到里面的元素
把嵌套配置交给 json_each,结果里出现了 panel 和 sizes 两行,却没有 theme 或每个尺寸。json_each 在这里展开的是根对象的直接孩子;一个孩子是对象、另一个孩子是数组,它不会自动把它们里面的内容也铺平成明细。
需要递归检查全部字段时,可以使用 json_tree,再明确选择容器还是叶子。下面通过 Python 连接内存 SQLite,分别打印顶层条目和叶子路径。保存为 demo.py,用 python demo.py 运行;JSON 是代码内固定数据,要求 SQLite 构建包含 JSON 支持。
AI生成概念插图:顶层节点与更深的叶子属于不同遍历范围,放大镜表示递归检查;不是查询工具截图。
import json
import sqlite3
document = json.dumps({
"panel": {"theme": "blue", "note": None},
"sizes": [2, 4],
})
db = sqlite3.connect(":memory:")
try:
top = db.execute(
"SELECT key, type FROM json_each(?) ORDER BY key", (document,)
).fetchall()
assert top == [("panel", "object"), ("sizes", "array")]
print("top:", top)
leaves = db.execute("""
SELECT fullkey, type, atom
FROM json_tree(?)
WHERE type NOT IN ('object', 'array')
ORDER BY fullkey
""", (document,)).fetchall()
assert leaves == [
("$.panel.note", "null", None),
("$.panel.theme", "text", "blue"),
("$.sizes[0]", "integer", 2),
("$.sizes[1]", "integer", 4),
]
print("leaves:", leaves)
nonnull = db.execute(
"SELECT COUNT(*) FROM json_tree(?) WHERE atom IS NOT NULL",
(document,),
).fetchone()[0]
assert nonnull == 3 and len(leaves) == 4
print("all leaves:", len(leaves), "nonnull atoms:", nonnull)
sizes = db.execute(
"SELECT key, value FROM json_each(?, '$.sizes') ORDER BY key",
(document,),
).fetchall()
assert sizes == [(0, 2), (1, 4)]
print("sizes:", sizes)
finally:
db.close()单层与递归应该按问题来选
top 输出两个顶层键及它们的类型。如果目标只是列出有哪些一级配置区块,这正是需要的结果;如果目标是查找任意深度的某个字段,才需要递归视角。json_tree 的结果包含容器本身,因此代码用 type 排除 object 与 array,留下四个叶子。
末尾的 json_each 增加路径 $.sizes,把展开起点移到这个数组,于是得到索引零与一及其数值。已知目标区块时,从指定路径开始能让查询含义更清楚。顶层值若本身是原始值,表值函数也有相应单行行为,不能把“始终返回多个孩子”当成所有输入的保证。
过滤叶子时,要决定是否保留空值
note 明确存在且值为 JSON null,因此叶子清单保留它,Python 中对应 None。atom IS NOT NULL 只留下三个非空原始值,把 note 一并排除了。对只搜索实际值的任务,这个筛选可能合适;对配置字段盘点,它会把“存在但为空”误变成“没有这项”。
fullkey 保存从根开始的完整路径,使不同容器内的同名字段仍能分辨。单独保存 key 往往不够:两个对象可以各有 theme,两个数组也都可以有索引零。代码给结果加 ORDER BY,保证演示稳定;不要把内部 id 或偶然输出顺序当作跨版本不变的业务编号。
value 对对象和数组会提供其 JSON 表示,而 atom 更适合读取原始叶子值。取哪一列应对应下游预期的类型,不能把一个表示数组的文本直接当成已经拆好的多行。布尔、数字、文本和空值也应保留 type,避免序列化后丢掉含义。
实际数据量大时,应先限制要检查的记录和路径,再展开所需部分。本例只展示遍历语义,没有评估大文档性能。遇到格式错误,应先核查输入是否是有效 JSON 和运行库是否具备该功能;不要用吞掉异常后返回空清单的方式掩盖解析失败。
资料核对日期:2026年10月2日。代码在本地 Python 3.12.14、SQLite 3.53.1 实际运行并通过断言;结果只对应文中给定输入。


