2

背景:我們使用PaperTrail來保存我們不斷變化的模型的歷史。現在我想查詢一個屬於某個客戶的項目。 PaperTrail可選擇存儲object_changes,我需要查詢此字段以瞭解何時使用此ID創建或更改爲此ID。查詢整數成員的jsonb數組

我的表看起來簡化這樣的:

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

您可能還喜歡'where_object_changes'方法。它應該是爲'object_changes'列做一個'where'子句的簡便方法。 –

+0

那麼你有你的答案嗎? –

回答

0

對於jsonbcontains operator @>做你問什麼:

獲取的所有行數是「customer_id」數組的一個元素:

SELECT * 
FROM versions 
WHERE object_changes->'customer_id' @> '5'; 

@>運營商期望jsonb作爲右操作數 - 或字符串文字,其有效期爲jsonb(而?預計text)。您在示例(5)中提供的沒有單引號的數字文字不能被強制爲jsonb(也不是text),它默認爲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]}'; 

,可以與一般的指數支持(更靈活,更大,更慢):

CREATE INDEX versions_object_changes_gin_idx ON versions 
USING gin (object_changes jsonb_path_ops); 

相關:

According to the manual,操作者?搜索任何top-level key within the JSON value。測試表明,在數組中被認爲是「頂級鍵」,但數字(鍵必須是字符串畢竟)。因此,儘管此查詢將工作:

SELECT * FROM versions WHERE object_changes->'other' ? 'asht'; 

您的查詢在數組中尋找不會(甚至當你引用輸入字符串字面正確)。它只會找到(引號)字符串"5",歸類爲,但不包括(未加引號)的號碼5,歸類爲

旁白:Standard JSON only knows 4 primitives布爾。沒有整數原語(即使我聽說過的軟件,並補充說),整數,這是在Postgres的實現爲numeric一個公正的一個子集:

所以你的問題標題有點誤導,因爲沒有「整數」成員,嚴格來說。

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被跟蹤)。