SQLalchemy 过滤器嵌套在数组中的 jsonb
Sqlalchemy filter nested jsonb within arrays
我有一个 Postgres JSONB 字段,其中包含一些嵌套数组和其他 objects。
from sqlalchemy.dialects.postgresql import JSONB
class Family(db.Model):
meta = db.Column(JSONB)
joes = Family(meta=[
{
"name": "Joe",
"children": [
{
"name": "Jane"
},
{
"name": "Kate"
}
]
},
{
"name": "Lisa",
"children": [
{
"name": "Mary"
},
{
"name": "David"
}
]
},
])
有没有办法查询名字中包含特定子串的所有孩子?
如果我想查询 'a'
它应该让我 Mary, David, Kate, Jane
.
我在想,也许是这样的
Family.query.filter(
Family.meta.contains([{"children": [{"name": func.contains("a")}]}])
)
诀窍是使用 jsonb_array_elements()
取消嵌套一个或多个数组,然后过滤:
meta_value = literal_column('meta.value', type_=JSONB)
children_value = literal_column('children.value', type_=JSONB)
Family.query.\
with_entities(children_value['name'].astext).\
select_from(
Family,
func.jsonb_array_elements(Family.meta).alias('meta'),
func.jsonb_array_elements(
meta_value['children']).alias('children')).\
filter(children_value['name'].astext.contains('a'))
注意使用literal_column()
来引用集合返回函数的值jsonb_array_elements()
.
另一种选择是使用jsonb_path_query()
(在版本 12 中引入):
name = column('name', type_=JSONB)
Family.query.\
with_entities(name.astext).\
select_from(
func.jsonb_path_query(
Family.meta,
'$[*].children[*].name').alias('name')).\
filter(name.astext.contains('a')).\
all()
我有一个 Postgres JSONB 字段,其中包含一些嵌套数组和其他 objects。
from sqlalchemy.dialects.postgresql import JSONB
class Family(db.Model):
meta = db.Column(JSONB)
joes = Family(meta=[
{
"name": "Joe",
"children": [
{
"name": "Jane"
},
{
"name": "Kate"
}
]
},
{
"name": "Lisa",
"children": [
{
"name": "Mary"
},
{
"name": "David"
}
]
},
])
有没有办法查询名字中包含特定子串的所有孩子?
如果我想查询 'a'
它应该让我 Mary, David, Kate, Jane
.
我在想,也许是这样的
Family.query.filter(
Family.meta.contains([{"children": [{"name": func.contains("a")}]}])
)
诀窍是使用 jsonb_array_elements()
取消嵌套一个或多个数组,然后过滤:
meta_value = literal_column('meta.value', type_=JSONB)
children_value = literal_column('children.value', type_=JSONB)
Family.query.\
with_entities(children_value['name'].astext).\
select_from(
Family,
func.jsonb_array_elements(Family.meta).alias('meta'),
func.jsonb_array_elements(
meta_value['children']).alias('children')).\
filter(children_value['name'].astext.contains('a'))
注意使用literal_column()
来引用集合返回函数的值jsonb_array_elements()
.
另一种选择是使用jsonb_path_query()
(在版本 12 中引入):
name = column('name', type_=JSONB)
Family.query.\
with_entities(name.astext).\
select_from(
func.jsonb_path_query(
Family.meta,
'$[*].children[*].name').alias('name')).\
filter(name.astext.contains('a')).\
all()