【问题标题】:Querying inside Postgres JSON arrays在 Postgres JSON 数组中查询
【发布时间】:2013-09-20 22:54:15
【问题描述】:

您将如何搜索存储在json 列中的数组中的元素? (更新:另请参阅jsonb 列的 9.4 更新答案。)

如果我有一个这样的 JSON 文档,存储在名为 blobjson 列中:

{"name": "Wolf",
 "ids": [185603363281305602,185603363289694211]}

我想做的是这样的:

SELECT * from "mytable" WHERE 185603363289694211 = ANY("blob"->'ids');

并取出所有匹配的行。但这不起作用,因为 "blob"->'ids' 返回 JSON 值,而不是 Postgres 数组。

如果可能的话,我还想在各个 ID 上建立一个索引。

【问题讨论】:

    标签: arrays json mongodb postgresql postgresql-9.3


    【解决方案1】:

    首先,尝试使用运算符 ->> 而不是 -> 从数组值中剥离 JSON 层。

    接下来,查询可以像这样工作:
    How do I query using fields inside the new PostgreSQL JSON datatype?

    索引可能会像这样工作:
    Index for finding an element in a JSON array

    【讨论】:

      【解决方案2】:

      以下原始答案仅适用于 Postgres 9.3。有关 Postgres 9.4 的答案,请参阅下面的更新。

      这建立在Erwin's referenced answers 之上,但对这个问题更加明确。

      本例中的 ID 为 bigints,因此创建一个辅助函数用于将 JSON 数组转换为 Postgres bigint 数组:

      CREATE OR REPLACE FUNCTION json_array_bigint(_j json)
        RETURNS bigint[] AS
      $$
      SELECT array_agg(elem::text::bigint)
      FROM json_array_elements(_j) AS elem
      $$
        LANGUAGE sql IMMUTABLE;
      

      我们可以在这里轻松地(也许更可重用)返回一个text 数组。我怀疑bigint 上的索引比text 快很多,但我很难在网上找到证据来支持这一点。

      建立索引:

      CREATE INDEX "myindex" ON "mytable" 
        USING GIN (json_array_bigint("blob"->'ids'));
      

      对于查询,这可以工作并使用索引:

      SELECT * FROM "mytable" 
        WHERE '{185603363289694211}' <@ json_array_bigint("blob"->'ids');
      

      这样做也适用于查询,但不使用索引:

      SELECT * FROM "mytable" 
        WHERE 185603363289694211 = ANY(json_array_bigint("blob"->'ids'));
      

      9.4 更新

      Postgres 9.4 引入了jsonb 类型。 This is a good SO answer about jsonb and when you should use it over json。简而言之,如果您曾经查询过 JSON,您应该使用 jsonb

      如果您将列构建为jsonb,则可以使用此查询:

      SELECT * FROM "mytable"
        WHERE blob @> '{"ids": [185603363289694211]}';
      

      @&gt; 是 Postgres 的包含运算符 documented for jsonb here。 感谢Alain's answer 让我注意到这一点。

      【讨论】:

      • +1 干得好。请注意,如果 JSON 数组中的元素不是唯一的,则结果中可能会出现重复的行。是的,处理bigint 通常比处理text 快。也使索引更小,但将elem::text::bigint 简化为elem::bigint。顺便说一句,Postgres 中完全有效的标识符不需要双引号。
      • 感谢您的帮助!不幸的是,从json 直接转换为bigint 不起作用。我必须先通过text
      • ANY(json_array_bigint("blob"-&gt;'ids'); --> 末尾缺少)
      【解决方案3】:

      我知道已经有一段时间了......

      在 postgresql-9.5 中,现在可以轻松查询它。

      select '{"name": "Wolf",
               "ids": [185603363281305602,185603363289694211]}'::jsonb
             @> '{"ids":[185603363281305602]}'
      

      我认为您应该改用jsonb 字段,然后您可以对其进行索引。

      CREATE INDEX idx_gin_ids ON mytable USING gin ((blob -> 'ids'));
      

      【讨论】:

      • 这似乎也适用于 Postgres 9.4。但需要注意的是 @&gt; 仅适用于 jsonb 列,而不适用于 json 列。 (这可能很好,我想不出你会选择json 而不是jsonb,但这个问题最初是针对还没有jsonb 的Postgres 9.3 提出的)
      • 另外我认为更好的例子是SELECT * from "mytable" WHERE blob @&gt; '{"ids": [185603363281305602]}';
      猜你喜欢
      • 1970-01-01
      • 2017-04-03
      • 2022-01-07
      • 2016-06-05
      • 2015-11-28
      • 1970-01-01
      • 2017-06-01
      • 2017-01-01
      相关资源
      最近更新 更多