[英]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.