测试给定 ID 是否存在于 JSON 列的任何行中

问题描述 投票:0回答:1

在我的 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。

如何编写查询来执行此操作?

(当然,这是一个人为的例子。)

sql json postgresql jsonpath postgresql-performance
1个回答
1
投票

假设

jsonb
。 (对于普通
json
来说无法很好地扩展)。
为了使其快速,请使用Postgres 12添加的SQL/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 文档中创建一个实际的关系数据库?关键字“数据库规范化”。将使这样的查询变得更加简单和快捷。

© www.soinside.com 2019 - 2024. All rights reserved.