在我的 Postgres 13.10 数据库中,我有一个表
menus
,其中包含一个名为 dishes
的 JSON 列。此列包含以下格式的值:
{
"desserts": [
{"id": 1, "name": "chocolate cake"},
{"id": 2, "name": "banana split"}
],
"appetizers": [
{"id": 3, "name": "nachos"},
{"id": 4, "name": "mozzarella sticks"},
{"id": 5, "name": "buffalo wings"}
]
}
数据类型是
json
,但我确实可以选择将其更改为 jsonb
,如果这有助于提高查询性能。
给定开胃菜 ID 列表(例如 3 和 5),我需要确定此表中至少一行引用了哪些 ID。
如何编写查询来执行此操作?
(当然,这是一个人为的例子。)
假设
jsonb
。 (对于普通 json
来说无法很好地扩展)。SELECT *
FROM unnest ('{3,5}'::int[]) i(id)
WHERE EXISTS (
SELECT FROM menus
WHERE dishes @? format('$.*[*].id ? (@ == %s)', i.id)::jsonpath
);
这将搜索嵌套在
menus.dishes
顶级对象中的所有数组中的键“id”。或者限制为顶级关键“开胃菜”:
SELECT *
FROM unnest ('{3,5}'::int[]) i(id)
WHERE EXISTS (
SELECT FROM menus
WHERE dishes @? format('$.appetizers[*].id ? (@ == %s)', i.id)::jsonpath
);
确保在
menus(dishes)
上有 GIN 索引。理想情况下是 jsonb_path_ops
索引:
CREATE INDEX menus_dishes ON menus USING gin (dishes jsonb_path_ops);
主要功能是根据未嵌套的ID动态构建
jsonpath
表达式。这样,它适用于任意数量的输入 ID、JSON 文档中任意数量的顶级对象以及任意数量的嵌套数组项 - 同时仍然使用上述索引。
相关:
您是否考虑过从 JSON 文档中创建一个实际的关系数据库?关键字“数据库规范化”。将使这样的查询变得更加简单和快捷。