在PostgreSQL表“private_notion”中,我有一个JSONB列“record_map”,它可能包含也可能不包含嵌套对象,例如:
{
"blocks": {
"7a9abf0d-a066-4466-a565-4e6d7a960a37": {
"name": "block1",
"value": 1,
"child": {
"7a9abf0d-a066-4466-a565-4e6d7a960a37": {
"name": "block2",
"value": 2,
"child": {
"7a9abf0d-a066-4466-a565-4e6d7a960a37": {
"name": "block3",
"value": 3
}
}
},
"7a9abf0d-a066-4466-a565-4e6d7a960a38": {
"name": "block4",
"value": 4,
"child": {
"7a9abf0d-a066-4466-a565-4e6d7a960a39": {
"name": "block5",
"value": 5,
"child": {
"7a9abf0d-a066-4466-a565-4e6d7a960a40": {
"name": "block6",
"value": 6
}
}
}
}
},
}
}
}
}
字符串
为了检索数据,我们不知道哪个块有我们想要的数据,我们只有键。让我们假设我们正在寻找这个键为“7a 9abf 0 d-a066 -4466-a565- 4 e6 d 7a 960 a40”的对象,但我们不知道它位于父块4和块5的子块6中。另一个请求可能会寻找父块4,依此类推,我必须找到它的关键块。
整个代码看起来像这样:
async def get_private_notion_page(
site_uuid: str, page_id: str, db_session: AsyncSession
) -> PrivateNotionPage:
page_id_path = f"{page_id}" # page_id looks like this 7a9abf0d-a066-4466-a565-4e6d7a960a37
path = f"$.** ? (@.{page_id_path})"
stmt = text(
f"""
SELECT jsonb_path_query(record_map, {path})
FROM private_notion
WHERE site_id = {site_uuid}
"""
)
result = await db_session.execute(stmt)
result = result.scalars().first()
if result:
return result
else:
raise PrivateNotionSiteWasNotFound
型
所以我想出了以下查询语句,它们使用sqlalchemy“text”方法来接受原始SQL查询,但jsonb_path_query_array
和jsonb_path_query
抛出类似的错误; syntax error at or near "$"
。
page_id_path = f"{page_id}"
path = f"$.** ? (@.{page_id_path})"
stmt = text(
f"""
SELECT jsonb_path_query(record_map, {path})
FROM private_notion
WHERE site_id = {site_uuid}
"""
)
Error:
sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.PostgresSyntaxError'>: syntax error at or near "$"
[SQL:
SELECT jsonb_path_query(record_map, $.** ? (@.7a9abf0d-a066-4466-a565-4e6d7a960a37))
FROM private_notion
WHERE site_id = 26f52d8e-a380-46ab-9131-e6f7f62c528f
]
型
我后来了解到“$**运算符在SQL查询中无效,相反,您可以使用jsonb_path_query_array函数递归搜索JSONB对象的所有级别。”
显然,我在重构代码后得到了同样的错误。
page_id_path = f"{page_id}"
path = f"$[*] ? (@ like_regex {page_id_path})"
stmt = text(
f"""
SELECT jsonb_path_query_array(record_map -> 'block', {path})
FROM private_notion
WHERE site_id = {site_uuid}
"""
)
Error:
sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.PostgresSyntaxError'>: syntax error at or near "$"
[SQL:
SELECT jsonb_path_query_array(record_map -> 'block', $[*] ? (@ like_regex 7a9abf0d-a066-4466-a565-4e6d7a960a37))
FROM private_notion
WHERE site_id = 26f52d8e-a380-46ab-9131-e6f7f62c528f
]
型
我的问题有两个方面,这个错误是怎么回事?有没有更好的方法通过JSONB列中的键来检索嵌套对象?谢谢你的时间。
1条答案
按热度按时间deyfvvtc1#
这将提取任何级别的整个对象,其中包含您的目标基于uuid的键:demo at db<>fiddle
字符串
| jsonb_path_query|
| --|
| { "7a9abf0d-a066-4466-a565-4e6d7a960a37": { "name": "block1", "child": { "7a9abf0d-a066-4466-a565-4e6d7a960a37": { "name": "block2", "child": { "7a9abf0d-a066-4466-a565-4e6d7a960a37": { "name": "block3", "value": 3 } }, "value": 2 }, "7a9abf0d-a066-4466-a565-4e6d7a960a38": { "name": "block4", "child": { "7a9abf0d-a066-4466-a565-4e6d7a960a39": { "name": "block5", "child": { "7a9abf0d-a066-4466-a565-4e6d7a960a40": { "name": "block6", "value": 6 } }, "value": 5 } }, "value": 4 } }, "value": 1 }} |
| { “7a9abf0d-a066-4466-a565-4e6d7a960a37”:{ “name”:“block2”, “child”:{ “7a9abf0d-a066-4466-a565-4e6d7a960a37”:{ “name”:“block3”, “value”:3 } }, “value”:2 }, “7a9abf0d-a066-4466-a565-4e6d7a960a38”:{ “name”:“block4”, “child”:{ “7a9abf0d-a066-4466-a565-4e6d7a960a39”:{ “name”:“block5”, “child”:{ “7a9abf0d-a066-4466-a565-4e6d7a960a40”:{ “name”:“block6”, “value”:6 } }, “value”:5 } }, “value”:4 }个文件夹|
| { “7a9abf0d-a066-4466-a565-4e6d7a960a37”:{ “name”:“block3”, “value”:3 }个文件夹|
注意通过取消嵌套的对象复制:它们既单独出现,也出现在每个匹配的父结构中。
型
型
1.使用
.**
访问器时,默认使用strict
模式。1.可以使用SQLAlchemy JSONPath类型传递表达式。