背景:我们使用PaperTrail来保留我们不断变化的模型的历史。现在我想查询属于某个客户的Item。 PaperTrail可选地存储object_changes
,我需要查询此字段以了解何时使用此ID创建或更改为此ID。
我的表看起来像这样简化:
item_type | object_changes
----------|----------------------------------------------------------
"Item" | {"customer_id": [null, 5], "other": [null, "change"]}
"Item" | {"customer_id": [4, 5], "other": ["unrelated", "change"]}
"Item" | {"customer_id": [5, 6], "other": ["asht", "asht"]}
如何查询从ID 5更改的元素(所以上面的所有行)?我试过了:
SELECT * FROM versions WHERE object_changes->'customer_id' ? 5;
哪个让我:
ERROR: operator does not exist: jsonb ? integer LINE 1: ...T * FROM versions WHERE object_changes->'customer_id' ? 5; ^ HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
答案 0 :(得分:0)
对于 jsonb
,contains operator @>
符合您的要求:
获取数字 5 所有的行" customer_id"阵列:
SELECT *
FROM versions
WHERE object_changes->'customer_id' @> '5';
@>
运算符需要jsonb
作为右操作数 - 或者对jsonb
有效的字符串文字(而?
期望text
)。您在示例中提供的数字文字没有单引号(5
)无法强制转换为jsonb
(也不是text
),默认为{{1} }。因此错误消息。相关:
这可以通过不同的索引样式来支持。对于我上面建议的查询,使用表达式索引(专用,小和快):
integer
此替代查询也有效:
CREATE INDEX versions_object_changes_customer_id_gin_idx ON versions
USING gin ((object_changes->'customer_id'));
并且可以通过一般索引支持(更通用,更大,更慢):
SELECT * FROM versions WHERE object_changes @> '{"customer_id": [5]}';
相关:
According to the manual,运营商 CREATE INDEX versions_object_changes_gin_idx ON versions
USING gin (object_changes jsonb_path_ops);
搜索任何?
。测试表明数组中的字符串被视为"顶级键" ,但数字是 不是 (毕竟键必须是字符串)。因此,虽然这个查询可行:
top-level key within the JSON value
您在数组中查找数字的查询将不会(即使您正确引用输入字符串文字)。它只会找到(引用!)字符串SELECT * FROM versions WHERE object_changes->'other' ? 'asht';
,分类为键,但不会找到(未引用的)数字"5"
,分类为值
除此之外:Standard JSON only knows 4 primitives:字符串,数字,布尔和 null 。没有整数原语(即使我听说过添加的软件), integer 只是 number 的一个子集,已实现作为Postgres中的5
:
所以你的问题标题有点误导,因为没有"整数"严格来说,成员。
答案 1 :(得分:0)
使用横向联接和jsonb_array_elements_text
函数来处理每一行的object_changes
:
SELECT DISTINCT v.* FROM versions v
JOIN LATERAL jsonb_array_elements_text(v.object_changes->'customer_id') ids ON TRUE
WHERE ids.value::int = 5;
DISTINCT
仅在您要查找的customer_id
在阵列中多次出现时才有必要(如果其他字段已更改,但无论如何都会跟踪customer_id
)。