19

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

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

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

我想做的是:

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

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

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

4

3 回答 3

14

The following original answer applies only for Postgres 9.3. For a Postgres 9.4 answer, see the Update below.

This builds on Erwin's referenced answers, but is a little bit more explicit to this question.

The IDs in this case are bigints, so create a helper function for converting a JSON array to a Postgres bigint array:

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;

We could just have easily (and perhaps more re-usably) returned a text array here instead. I suspect indexing on bigint is a lot faster than text but I'm having a difficult time finding evidence online to back that up.

For building the index:

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

For querying, this works and uses the index:

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

Doing this will also work for querying, but it doesn't use the index:

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

Update for 9.4

Postgres 9.4 introduced the jsonb type. This is a good SO answer about jsonb and when you should use it over json. In short, if you're ever querying the JSON, you should use jsonb.

If you build your column as jsonb, you can use this query:

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

The @> is Postgres' contains operator, documented for jsonb here. Thanks to Alain's answer for bringing this to my attention.

于 2013-09-16T20:07:04.030 回答
5

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

接下来,查询可以这样工作:
如何使用新的 PostgreSQL JSON 数据类型中的字段进行查询?

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

于 2013-09-16T18:04:33.383 回答
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'));
于 2015-05-13T22:34:23.687 回答