简体   繁体   English

SqlAlchemy 从jsonb对象的值中搜索,postgresql

[英]SqlAlchemy search from values of jsonb objects, postgresql

I have a jsonb field in a table having values of the form我在表格中有一个 jsonb 字段,其值的形式为

from sqlalchemy.dialects.postgresql import JSONB

class Product(db.Model):
    __tablename__ = 'tbl_product'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(JSONB, nullable=False, index=True, unique=True)
    slug = db.Column(JSONB, nullable=False, index=True, unique=True)

And I have product names in different languages:我有不同语言的产品名称:

name = {'en': 'Notebook', 'de': 'Notizbuch', ..... }

I want to make search from column name but I don't know in which language it appears, here I can search on specific language:我想从列名进行搜索,但我不知道它以哪种语言出现,在这里我可以搜索特定的语言:

def get_product_by_name(name, lang):
    q = Product.query
    q = q.filter(Product.slug[lang].as_string() == slug)

    return q.first()

1Q: How can I search without language information? 1Q:没有语言信息怎么搜索? 2Q: Can I order product with language? 2Q:我可以订购带有语言的产品吗? Somethign like this:像这样的东西:

def get_products(lang):
    q = Product.query
    q = q.order_by(Product.name[lang].asc())

    return q.all()

 

After @GordThompson's comment, I improved the query to use jsonb_each_text , it became a lot more straigtforward.在@GordThompson 发表评论后,我改进了查询以使用jsonb_each_text ,它变得更加直截了当。

stmt = (
    select(Product)
    .join(func.jsonb_each_text(Product.name).alias("e"), onclause=True)
    .filter(text("e.value = :target_value")
)

For reference, here is the documentation for the JSON-functions of PostgreSQL .作为参考,这里是PostgreSQL 的 JSON 函数的文档


Full script demo:完整的脚本演示:

import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

metadata_obj = sa.MetaData()

t = sa.Table(
    "t73345077",
    metadata_obj,
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("name", postgresql.JSONB),
)

engine = sa.create_engine(
    "postgresql+psycopg2://postgres:postgres@localhost:5432/postgres",
    echo=True,
    future=True,
)

metadata_obj.create_all(engine)

with engine.begin() as con:
    con.execute(
        sa.insert(t),
        [
            {"name": {"en": "goat", "fr": "chevre"}},
            {"name": {"en": "cow", "fr": "vache"}},
            {"name": {"en": "sheep", "fr": "mouton"}},
        ],
    )

with engine.connect() as con:
    r = con.execute(
        sa.select(t)
        .join(sa.func.jsonb_each_text(t.c.name).alias("e"), onclause=True)
        .filter(sa.text("e.value = :target_value"),
        dict(target_value="vache"),
    )
    print(r.all())  # gives [(2, {'en': 'cow', 'fr': 'vache'})]

The query emits the following:查询发出以下内容:

SELECT t73345077.id, t73345077.name 
FROM t73345077 JOIN jsonb_each_text(t73345077.name) AS e ON true 
WHERE e.value = 'vache'

For posterity, I am keeping are the other queries I found that worked, but did not use bind params, so use the query above.对于后代,我保留的是我发现有效但未使用绑定参数的其他查询,因此请使用上面的查询。

sa.select(t).filter(
    sa.func.jsonb_path_exists(
        t.c.name,
        '$.keyvalue().value ?(@ == "vache")'
    )
)

sa.select(t).filter(sa.text("name @? '$.** ? (@ == \"vache\")';"))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM