【问题标题】:PostgreSQL JSONB - query condition with variable key namesPostgreSQL JSONB - 具有可变键名的查询条件
【发布时间】:2016-11-15 18:22:34
【问题描述】:

我已经阅读了各种 JSONB 教程:

考虑以下示例。

有一个名为plans。它有以下列:

  1. id(整数,自增主键)。
  2. name(字符串)。
  3. structure (jsonb)。

结构列有一个具有以下结构的常规 JSON 对象:

{
  "some_unique_id": {
    "key1": "valueA",   // Fixed key name.
    "key2": "valueB"    // Fixed key name.
  },
  "another_unique_id": {
    "key1": "valueC",   // Fixed key name.
    "key2": "valueB"    // Fixed key name.
  },
  ...                   // can go on up to a 1000 items.
}

注意:最外面的键是动态的。它们随每件商品而变化。 这些值只是常规的 JSON 对象。没什么特别的。

我使用 UUID 作为结构中的键,因此如果我知道它的 UUID,就可以轻松查找和检索特定值。

另一种选择是让我的结构成为一个对象数组(并将 UUID 作为一个值放入每个对象中),如下所示:

[
  {
    "uuid": "some_unique_id",
    "key1": "valueA",   // Fixed key name.
    "key2": "valueB"    // Fixed key name.
  },
  {
    "uuid": "another_unique_id",
    "key1": "valueC",   // Fixed key name.
    "key2": "valueB"    // Fixed key name.
  },
  ...                   // can go on up to a 1000 items.
]

在后一种方法中,要使用其 UUID 检索特定对象,我必须遍历整个数组并匹配每个对象的 uuid 键。

所以,我选择了第一种方法。

该表有 3 条记录。对于这个问题,idname 列的值并不重要。

3条记录中structure列的实际值如下。

记录 1:

{
  "bab6246d-802c-4b80-af41-ab15fd1541b4": {
    "name": "Sanskrit",
    "children_uuids": [
      "fa42b4b2-a958-42f1-af33-314e8e1fb6a6",
      "3aeeadfe-6ad4-4229-85a5-5de030c08014"
    ],
    "is_invisible_node": true,
    "tags": [
      "paper",
      "course_paper"
    ],
    "type": "course_paper"
  },
  "dbc33473-8453-4cf9-8ecf-d8013283b0d8": {
    "name": "French",
    "children_uuids": [
      "4bf65ff9-3b11-42d5-a744-adcd1fd5a953"
    ],
    "is_invisible_node": true,
    "tags": [
      "paper",
      "course_paper"
    ],
    "type": "course_paper"
  }
}

记录 2:

{
  "ed6164d0-fdc0-4259-90a5-fd60d9d716dc": {
    "name": "Pen and Paper Assessment 1",
    "children_uuids": [

    ],
    "is_invisible_node": false,
    "tags": [
      "paper",
      "assessment"
    ],
    "type": "assessment"
  },
  "059d0116-bca2-49f1-b333-58c4dbec8566": {
    "name": "Content",
    "children_uuids": [

    ],
    "is_invisible_node": false,
    "tags": [
      "paper",
      "assessment"
    ],
    "type": "assessment"
  }
}

记录 3:

{
  "63619c7f-fa73-49af-9df5-4be1eb38cee5": {
    "name": "Q12",
    "children_uuids": [

    ],
    "is_invisible_node": true,
    "tags": [
      "paper",
      "regular_paper"
    ],
    "type": "regular_paper"
  },
  "56eed164-17f7-48e9-b3ce-b5b469e8cb0e": {
    "name": "Q13",
     "children_uuids": [

    ],
    "is_invisible_node": false,
    "tags": [
      "paper",
      "regular_paper"
    ],
    "type": "regular_paper"
  },
  "69d202c1-5c23-412f-860d-1a5d705c31b3": {
    "name": "Q14",
    "children_uuids": [

    ],
    "is_invisible_node": false,
    "tags": [
      "paper",
      "regular_paper"
    ],
    "type": "regular_paper"
  }
}

现在,我如何编写查询来完成以下两件事?

  • 我想获取所有记录,其中包含is_invisible_node 属性设置为true 的任何对象。
  • 我想获取所有包含regular_paper 作为其tags 之一的对象

感谢您阅读本文!任何帮助将不胜感激。

【问题讨论】:

    标签: json postgresql jsonb


    【解决方案1】:

    我想获取所有包含 is_invisible_node 属性设置为 true 的对象的所有记录。

    使用jsonb_each()检索二级对象:

    select id, uuid.key uuid
    from 
        plans, 
        jsonb_each(structure) uuid
    where (value->>'is_invisible_node')::boolean;
    
     id |                 uuid                 
    ----+--------------------------------------
      1 | bab6246d-802c-4b80-af41-ab15fd1541b4
      1 | dbc33473-8453-4cf9-8ecf-d8013283b0d8
      3 | 63619c7f-fa73-49af-9df5-4be1eb38cee5
    (3 rows)
    

    select distinct id
    from 
        plans, 
        jsonb_each(structure) uuid
    where (value->>'is_invisible_node')::boolean;
    
     id 
    ----
      1
      3
    (2 rows)    
    

    我想获取所有包含 regular_paper 作为其标签之一的对象。

    json对象tags是一个数组,所以用jsonb_array_elements_text()解除嵌套:

    select uuid.key uuid
    from 
        plans, 
        jsonb_each(structure) uuid,
        jsonb_array_elements_text(value->'tags') tag
    where tag = 'regular_paper';
    
                     uuid                 
    --------------------------------------
     56eed164-17f7-48e9-b3ce-b5b469e8cb0e
     63619c7f-fa73-49af-9df5-4be1eb38cee5
     69d202c1-5c23-412f-860d-1a5d705c31b3
    (3 rows)
    

    【讨论】:

    • 太棒了!谢谢。
    • 只是确认一下——这些查询会使用structure 列上的jsonb_path_ops GIN 索引吗?还是需要“常规” GIN 索引? (参考:blog.2ndquadrant.com/jsonb-type-performance-postgresql-9-4
    • @Anjan 不,jsonb_eachjsonb_array_elements[_text] 之类的函数(设置返回 json 函数)根本不能使用索引。要使用索引,您需要规范化您的数据库结构。
    • 不,索引不会被使用,因为它只支持 @> 运算符,所以它会很有帮助,例如在搜索uuid。使用 decomposing 函数(如 jsonb_each().
    • 当然,这会起作用,但您不会知道满足哪个特定的uuid 条件。该条件将涉及整行。我不认为这是你想要的。或者您将有一个数组用于一个 uuid - 这是一个解决方案,但是您不需要数组;)
    猜你喜欢
    • 2019-09-08
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 2021-07-27
    • 1970-01-01
    相关资源
    最近更新 更多