查找嵌套 JSON 文档中值大于 INT 的行

Find rows where value in nested JSON document is greater than INT

我是一个 PostgreSQL 新手。但我认为在关系数据库中使用 json/jsonb 听起来很有趣。

//仅供参考:我尝试通过 C# .NET Core WebAPI 和 Dapper 实现它

我想要一个带有(多维)json 列的 table,例如:

 id                                   | data                                                             
 _____________________________________|_________________________________________________________________________________
                                      |                                                                                 
 4BF30FE6-D7DD-480B-8592-DC9676576FEF | { timestamps:{ "created":1578614541, "modified":1578615707 }, "type":"single"}  
 1AC2CD8F-09D0-456C-9FD4-B63E354BD324 | { timestamps:{ "created":1578614676, "modified":1578615921 }, "type":"multiple"}
 50AD2D82-5919-4555-BCC2-B24E0DE24263 | { timestamps:{ "created":1578614552, "modified":1578615784 }, "type":"single"}  
 8C3BE671-17D1-49FD-A891-D5E69FDF7FC2 | { timestamps:{ "created":1578614685, "modified":1578615173 }, "type":"single"}   

我想获取所有 data::timestamps.created 大于 1578614670 的 ID。

伪代码:

SELECT id, data FROM table WHERE data::timestamps.created > 1578614670;
 id                                   | data                                                             
 _____________________________________|_________________________________________________________________________________
                                      |                                                                                 
 1AC2CD8F-09D0-456C-9FD4-B63E354BD324 | { timestamps:{ "created":1578614676, "modified":1578615921 }, "type":"multiple"}
 8C3BE671-17D1-49FD-A891-D5E69FDF7FC2 | { timestamps:{ "created":1578614685, "modified":1578615173 }, "type":"single"}   

有没有简单的方法可以做到这一点?

编辑:删除了 Erwin 指出的错误(并投票 )。保留其余答案,因为其他信息可能有用。

下面会按照你的要求去做。这里是 table.

CREATE TABLE example (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  data jsonb NOT NULL
);

一旦您插入数据,这将执行您想要的查询。

SELECT id, data
FROM "table"
WHERE (data->'timestamps'->>'created')::int8 > 1578614670;

这会从 JSONB column as text, and then converts to an 8-byte integer (64-bit int). For a sequential scan on a large table, this can be quite slow, so you'll want an expression index 中提取 "created" 条目。

CREATE INDEX created_idx ON "table" ((data->'timestamps'->>'created')::int8);

在比较之前降低嵌套的多个级别#>> operator is useful. Then cast the extracted text to an appropriate numeric type

SELECT id, data FROM tbl
WHERE (data #>> '{timestamps,created}')::numeric > 1578614670;

相当于:

...
WHERE (data -> 'timestamps' ->> 'created')::numeric > 1578614670;

numeric 是安全的选择。如果您知道 created 中的所有数字都小于 2^31 或 2^63,您可以分别使用 integerbigint。您的示例显示了有效的数字文字,但这必须适用于 所有 提取的值。

为了加快速度,考虑像 Miles 建议的表达式索引,转换为适当的数字类型 - 但要有适当的括号。

CREATE INDEX tbl_data_created_idx
ON tbl (((data #>> '{timestamps,created}')::numeric)); -- all parentheses required

相关:

此处的所有内容都适用于类型 jsonjsonb,在这方面都是一样的。

db<>fiddle here(同时演示)