PostgreSQL - 用于选择JSON

时间:2017-10-04 16:55:06

标签: json postgresql nosql jsonb marten

我的数据库中有这个JSON:

  {
      "Id": 1,
      "Questions": [
        {
          "QuestionId": 6,
          "Description": "Question 1",
          "Alternatives": [
            {
              "Index": 1,
              "CorrectAnswer": false,
              "AlternativeId": 26,
              "QuestionId": 6,
              "Description": "Alternative one",
              "Selected": false
            },
            {
              "Index": 2,
              "CorrectAnswer": true,
              "AlternativeId": 27,
              "QuestionId": 6,
              "Description": "Alternative two",
              "Selected": false
            }
          ]
        },
        {
          "QuestionId": 7,
          "Description": "Question 2",
          "Alternatives": [
            {
              "Index": 1,
              "CorrectAnswer": false,
              "AlternativeId": 26,
              "QuestionId": 6,
              "Description": "Alternative one",
              "Selected": false
            },
            {
              "Index": 2,
              "CorrectAnswer": true,
              "AlternativeId": 27,
              "QuestionId": 6,
              "Description": "Alternative two",
              "Selected": false
            }
          ]
        }
      ]
    }

我在这份文件中只能提出一个问题。我尝试了以下查询:

select data#>'{Questions}' from db.my_table
where (data #> '{Questions,0,QuestionId}')::numeric = 6;

SELECT data ->> 'Questions' AS Questions FROM db.my_table
WHERE (data -> 'Questions' ->> 'QuestionId')::numeric = 6;

SELECT data ->> 'Questions' AS Questions FROM db.my_table
WHERE data  -> 'Questions' ->> 'QuestionId' = '6'

我能做错什么?我总是得到0个受影响行的返回。

文档:

https://www.postgresql.org/docs/current/static/datatype-json.html https://www.postgresql.org/docs/current/static/functions-json.html

欢迎每一位帮助!

1 个答案:

答案 0 :(得分:2)

让我们先谈谈你的每个问题:

select data#>'{Questions}' from db.my_table
where (data #> '{Questions,0,QuestionId}')::numeric = 6;

这实际上失败了(ERROR: cannot cast type json to numeric)。您可以将where子句中的运算符更改为#>>,它将不再出错 - #>>返回可以强制转换为数字的文本。此时,查询将返回整个Questions数组,而不是您想要的特定问题。

为什么呢?因为所有问题都属于同一行。

SELECT返回行,其WHERE子句对行进行操作。由于您在一行中有许多值,因此使用此方法有条件地提取json子对象时会遇到问题。

其他两个查询成功运行但没有产生结果:

SELECT data ->> 'Questions' AS Questions FROM db.my_table
WHERE (data -> 'Questions' ->> 'QuestionId')::numeric = 6;

SELECT data ->> 'Questions' AS Questions FROM db.my_table
WHERE data  -> 'Questions' ->> 'QuestionId' = '6'

在这两种情况下,您都要在json blob中索引不存在的字段。 Questions是一个数组,因此使用字符串对其进行索引并不起作用,但json足够宽松,可以让您尝试。换句话说,条款WHERE data -> 'Questions' ->> 'QuestionId' = '6'根本不匹配任何行。

诀窍是将每个问题排成一行。这有点复杂,但并不难做到。

首先,查看函数json_array_elements,看起来它应该工作 - 它需要一个json数组并将每个元素作为一行返回一个列(名为" value") 。乍一看,似乎你应该能够做一些形式的事情:

SELECT value FROM json_array_elements(...)
WHERE value ->> 'QuestionId'::numeric = 6;

不幸的是,它并不那么简单。这是一个有效的查询:

SELECT datatable.question
  FROM my_table,
    json_array_elements(my_table.data -> 'Questions') AS datatable(question)
 WHERE (question->>'QuestionId')::numeric = 6;

好的,让我们稍微打破一下。最终,它会返回我们使用question调用创建的datatable表的json_array_elements字段。 question是一个json对象,我们过滤只返回QuestionID == 6的对象。

但是,请注意,我们还要从my_table中进行选择,因为最终是数据的来源。在这种情况下,我们会在my_tabledatatable之间进行无约束的笛卡尔联接。这不好,可能不会很好地扩展。但它适用于我们目前只有几行的情况。

希望能给你一个开始的地方。