2015-01-29 20 views
5

Tôi có một trường JSONB đôi khi có các khóa lồng nhau. Ví dụ:Bộ lọc SQLAlchemy theo các khóa lồng nhau trong JSONB

{"nested_field": {"another URL": "foo", "a simple text": "text"}, "first_metadata": "plain string", "another_metadata": "foobar"}

Nếu tôi làm .filter(TestMetadata.metadata_item.has_key(nested_field))
tôi nhận được hồ sơ này.

Tôi làm cách nào để tìm kiếm sự tồn tại của khóa lồng nhau? ("a simple text")

Trả lời

10

Với SQLAlchemy sau nên làm việc cho chuỗi thử nghiệm của bạn:

class TestMetadata(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    metadata_item = Column(JSONB) 

theo SQLAlchemy documentation of JSONB (tìm kiếm hoạt động chỉ số đường ví dụ):

expr = TestMetadata.metadata_item[("nested_field", "a simple text")] 
q = (session.query(TestMetadata.id, expr.label("deep_value")) 
    .filter(expr != None) 
    .all()) 

mà nên tạo ra SQL dưới đây:

SELECT testmetadata.id AS testmetadata_id, 
     testmetadata.metadata_item #> %(metadata_item_1)s AS deep_value 
FROM testmetadata 
WHERE (testmetadata.metadata_item #> %(metadata_item_1)s) IS NOT NULL 
-- @params: {'metadata_item_1': u'{nested_field, a simple text}'} 
+4

Awesom e ... IMHO nó không phải là rõ ràng rằng chỉ số Path là một JSON lồng nhau, nhưng có lẽ nó chỉ là tôi. Nhân tiện - để kiểm tra dựa trên giá trị tôi muốn sử dụng nội bộ: '.filter (TestMetadata.metadata_item [key] .astext == value)' Trường hợp khóa là bộ tóan – Boaz

+1

Chắc chắn, mặc dù câu hỏi của bạn là nhiều hơn * kiểm tra sự tồn tại * và không * kiểm tra giá trị * loại điều. – van

+1

bạn hoàn toàn đúng ... Tôi cần cả hai (và rõ ràng là impl. Khác nhau vì has_key không hỗ trợ một bộ dữ liệu) – Boaz

1

Truy vấn này kiểm tra sự tồn tại của lĩnh vực lồng nhau với ? operator, sau khi giải nén các đối tượng JSON lồng nhau với -> operator:

SELECT EXISTS (
    SELECT 1 
    FROM testmetadata 
    WHERE metadata_item->'nested_field' ? 'a simple text' 
    ); 

Lưu ý rằng một chỉ số GIN đồng bằng không hỗ trợ truy vấn này. Bạn sẽ cần một số expression index trên metadata_item->'nested_field' để thực hiện việc này nhanh chóng.

CREATE INDEX testmetadata_special_idx ON testmetadata 
USING gin ((metadata_item->'nested_field')); 

Có một số example in the manual cho trường hợp tương tự.

Các vấn đề liên quan