查询整数成员

时间:2017-09-13 15:24:54

标签: ruby-on-rails postgresql jsonb paper-trail-gem postgresql-9.6

背景:我们使用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.

2 个答案:

答案 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)。