Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON fields #26

Open
Goomba41 opened this issue Feb 19, 2019 · 5 comments
Open

JSON fields #26

Goomba41 opened this issue Feb 19, 2019 · 5 comments

Comments

@Goomba41
Copy link

Is it possible to support the filtering function by the key values of JSON fields?
SQLAlchemy has a JSON_EXTRACT function and I can filter Model.json_column ['key'] == value

@juliotrigo
Copy link
Owner

Hi @Goomba41 , thanks for your request.

It is currently not supported by the library but it'd be a nice addition to it if we can integrate it.

I am going to start looking into it and will keep you posted here.

@btoro
Copy link

btoro commented May 28, 2020

@Goomba41,

What I ended up doing is using the hybrid_property decorators to "recreate" the fields from the JSON field. This then allows the filter function to work.

class report(Base):
    """ Table to store reports. """
    __tablename__ = "report"

    id = Column(Integer, primary_key=True, autoincrement=True)
    report = Column(JSONB)

    @hybrid_property
    def created(self):
        return self.report['created']

Its not ideal since you have to define them with each change, but it works

@tiru1930
Copy link

@juliotrigo is there any progress on this

@tiru1930
Copy link

tiru1930 commented Jul 12, 2021

@juliotrigo @Goomba41 @btoro

Looks like these changes might work for jsonb parsing

in sorting.py and filtering.py , I have added below code

if self.sort_spec.get("jsonb_path", None):
      jsonb_keys = self.sort_spec.get("jsonb_path").split("__")
      print(jsonb_keys)
      sqlalchemy_field = sqlalchemy_field.cast(JSONB)[tuple(jsonb_keys)]



filter_spec = [
{"or": [
  {'field': 'metrics', 'op': '==', 'value': '0.8', 'jsonb_path': "metrics__f1"},
  {'field': 'id', 'op': '==', 'value': '1'}
]}
]

sort_spec = [
{'field': 'metrics', 'direction': 'desc', "nullslast": True, 'jsonb_path': "metrics__f1"},
{'field': 'metrics', 'direction': 'asc', "nullslast": True, 'jsonb_path': "metrics__accuracy"},
]

@itsAlexK
Copy link

itsAlexK commented Dec 21, 2021

Here's a simple patch for anyone who ends up here for JSONB

import sqlalchemy_filters
import types
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy_filters import (  # noqa
    apply_filters,
    apply_loads,
    apply_pagination,
    apply_sort,
    filters,
    loads,
    models,
    pagination,
    sorting,
)


class JSONPatchField(models.Field):

    def get_sqlalchemy_field(self):

        sub_field_names = None

        if "." in self.field_name:
            field_name, *sub_field_names = self.field_name.split(".")
        else:
            field_name = self.field_name

        if field_name not in self._get_valid_field_names():
            raise models.FieldNotFound(
                "Model {} has no column `{}`.".format(self.model, field_name)
            )
        sqlalchemy_field = getattr(self.model, field_name)

        # If it's a hybrid method, then we call it so that we can work with
        # the result of the execution and not with the method object itself
        if isinstance(sqlalchemy_field, types.MethodType):
            sqlalchemy_field = sqlalchemy_field()
        elif isinstance(sqlalchemy_field.type, JSONB) and sub_field_names:
            sqlalchemy_field = sqlalchemy_field[sub_field_names]
            sqlalchemy_field = sqlalchemy_field.astext
        return sqlalchemy_field


sqlalchemy_filters.filters.Field = JSONPatchField
sqlalchemy_filters.loads.Field = JSONPatchField
sqlalchemy_filters.pagination.Field = JSONPatchField
sqlalchemy_filters.sorting.Field = JSONPatchField

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants