Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy: filtering on values stored in nested list of the JSONB field

Lets say I have a model named Item, which contains a JSONB field data. One of the records has the following JSON object stored there:

{
    "name": "hello",
    "nested_object": {
        "nested_name": "nested"
    },
    "nested_list": [
        {
            "nested_key": "one"
        },
        {
            "nested_key": "two"
        }
    ]
}

I can find this record by filtering on the name field as such:

Session().query(Item).filter(Item.data["name"] == "hello")

I can find this record by filtering on the nested object likewise as such:

Session().query(Item).filter(Item.data[("nested_object","nested_name")] == "hello")

However I am struggling to find a way to find this record by filtering on the value of the item stored within the nested list. In other words I want to find the record above if the user has provided value "one", and I know to look for it in the key nested_key within the nested_list.

Is it possible to achieve this with SQLAlchemy filters available?

like image 1000
crosswind Avatar asked Sep 12 '16 23:09

crosswind


1 Answers

SQLAlchemy's JSONB type has the contains() method for the @> operator in Postgresql. The @> operator is used to check if the left value contains the right JSON path/value entries at the top level. In your case

data @> '{"nested_list": [{"nested_key": "one"}]}'::jsonb

Or in python

the_value = 'one'

Session().query(Item).filter(Item.data.contains(
    {'nested_list': [{'nested_key': the_value}]}
))

The method converts your python structure to suitable JSON string for the database.

In Postgresql 12 you can use the JSON path functions:

import json

Session().query(Item).\
    filter(func.jsonb_path_exists(
        Item.data,
        '$.nested_list[*].nested_key ? (@ == $val)',
        json.dumps({"val": the_value})))
like image 65
Ilja Everilä Avatar answered Oct 26 '22 22:10

Ilja Everilä