在Postgres JSON数组中查询

时间:2013-09-16 17:34:36

标签: arrays json mongodb postgresql postgresql-9.3

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

如果我有这样的JSON文档,则存储在名为json的{​​{1}}列中:

blob

我希望能够做的是:

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

并获取所有匹配的行。但这不起作用,因为SELECT * from "mytable" WHERE 185603363289694211 = ANY("blob"->'ids'); 返回JSON值,而不是Postgres数组。

如果可能的话,我还想建立个人ID的索引。

3 个答案:

答案 0 :(得分:14)

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

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

这种情况下的ID是bigint s,因此创建一个帮助函数,用于将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]}';

@>是Postgres'包含运算符documented for jsonb here。 感谢Alain's answer引起我的注意。

答案 1 :(得分:5)

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

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

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

答案 2 :(得分:4)

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

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

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

我认为您应该使用jsonb字段,然后您可以将其编入索引。

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