【问题标题】:Query a JSONB object array查询 JSONB 对象数组
【发布时间】:2022-01-11 07:14:16
【问题描述】:

我做了一个 DB Fiddle,看看这张桌子看起来像 https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/3382

表格中的数据如下所示

[
    {
        "id": 1,
        "form_id": 1,
        "questionnaire_response": [
            {
                "id": "1",
                "title": "Are you alive?",
                "value": "Yes",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "2",
                "title": "Did you sleep good?",
                "value": "No",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "3",
                "title": "Whats favorite color(s)?",
                "value": [
                    "Red",
                    "Blue"
                ],
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            }
        ]
    },
    {
        "id": 2,
        "form_id": 1,
        "questionnaire_response": [
            {
                "id": "1",
                "title": "Are you alive?",
                "value": "Yes",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "2",
                "title": "Did you sleep good?",
                "value": "Yes",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "3",
                "title": "Whats favorite color(s)?",
                "value": "Black",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            }
        ]
    },
    {
        "id": 3,
        "form_id": 1,
        "questionnaire_response": [
            {
                "id": "1",
                "title": "Are you alive?",
                "value": "Yes",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "2",
                "title": "Did you sleep good?",
                "value": "No",
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            },
            {
                "id": "3",
                "title": "Whats favorite color(s)?",
                "value": [
                    "Black",
                    "Red"
                ],
                "form_id": 0,
                "shortTitle": "",
                "description": ""
            }
        ]
    }
]

我有一个问题select * from form_responses,jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text) where (items.id = '3' AND items.value like '%Black%');

但不能像select * from form_responses,jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text) where (items.id = '3' AND items.value like '%Black%') AND (items.id = '2' AND items.value like '%Yes%');那样做多个对象

对象中的值字段也可以是数组或单个值.. 不可预测.. 我觉得我很接近但也不确定我是否首先使用了正确的查询。

任何帮助将不胜感激!

编辑

select * from form_responses where(
  questionnaire_response @> '[{"id": "2", "value":"No"},{"id": "3", "value":["Red"]}]')

似乎可行,但不确定这是否是最好的方法

【问题讨论】:

  • 尝试构建一个过滤系统,我可以在其中动态传递多个 ID 和值并从中获取整个记录 [{id: 1, value: 'Yes'},{id: 2, value: '否'}]

标签: json postgresql jsonb


【解决方案1】:

您当前的查询每项返回一个结果行。这些行都没有id = 3id = 2。如果您的目标是选择整个表单响应,则需要使用子查询(或者更确切地说,其中两个):

SELECT *
FROM form_responses
WHERE EXISTS(
    SELECT *
    FROM jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text)
    WHERE items.id = '3'
      AND items.value like '%Black%'
  )
  AND EXISTS(
    SELECT *
    FROM jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text)
    WHERE items.id = '2'
      AND items.value like '%Yes%'
  );

或者

SELECT *
FROM form_responses
WHERE (
    SELECT value
    FROM jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text)
    WHERE items.id = '3'
  ) like '%Black%'
  AND (
    SELECT value
    FROM jsonb_to_recordset(form_responses.questionnaire_response) as items(value text, id text)
    WHERE items.id = '2'
  ) like '%Yes%';

更好的选择是使用json path 查询:

SELECT *
FROM form_responses
WHERE questionnaire_response @@ '$[*]?(@.id == "1").value == "Yes"'
  AND questionnaire_response @@ '$[*]?(@.id == "3").value[*] == "Black"'
-- in one:
SELECT *
FROM form_responses
WHERE questionnaire_response @@ '$[*]?(@.id == "1").value == "Yes" && $[*]?(@.id == "3").value[*] == "Black"'

[*] 甚至对于有时字符串有时数组值具有正确的语义。如果您知道具有这些 id 的项目的索引,您甚至可以简化为

SELECT *
FROM form_responses
WHERE questionnaire_response @@ '$[0].value == "Yes" && $[2].value[*] == "Black"'

(dbfiddle demo)

【讨论】:

  • 在设置任何 jsonb_array_elements_text(value) 时出现“错误:无法从标量中提取元素”。在select * from form_responses where( questionnaire_response @> '[{"id": "2", "value":"No"},{"id": "3", "value":["Red"]}]') 查询中使用它的主要原因是什么?
  • 哦,我现在看到,即使对于第 3 项,值也可以是字符串,并不总是数组 - 我本来希望数据类型取决于您提出的问题。好处将是更清晰的语义,“正是数组的元素”与“数组的字符串表示形式在某处包含子字符串”是不同的查询。
  • 是的,jsonb_array_elements_text 无法处理这些数据(除非使用非常复杂的 CASE jsonb_type(value) OF … 表达式)。更好的选择:jsonpath!
  • 我看到你的编辑了!这太棒了!我没有研究过 jsonpath 但这似乎正是它的目的!
  • 对我来说看起来不错,但我对 jsonpath 性能也没有任何经验。我想你可以做类似questionnaire_response @? '$[*]?(@.id == "3" && @.value[*] == "Red" && @.value[*] == "Black")' 的事情来缩短它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2021-12-06
  • 2016-12-05
  • 2015-05-20
  • 2017-11-26
  • 2015-04-13
相关资源
最近更新 更多