[英]Postgres SQLAlchemy appending to existing jsonb record
I have a postgres DB with a jsonb field data
.我有一个带有 jsonb 字段
data
的 postgres 数据库。
I'd like to be able to append to an array of items in the field using sqlalchemy.我希望能够使用 sqlalchemy 附加到字段中的项目数组。
For example with the table:以表格为例:
id ![]() |
data![]() |
name![]() |
|
---|---|---|---|
1 ![]() |
[{"jon": {"age": 4}}, {"jane": {"age": 7}}] ![]() |
paul![]() |
|
2 ![]() |
[{"beryl": {"age": 3}}, {"victor": {"age": 9}}] ![]() |
dave![]() |
|
To do this in postgres I can use concatenate like this:要在 postgres 中执行此操作,我可以像这样使用连接:
UPDATE "test" SET "data" = "data" || '[{"beryl": {"age": 3}}, {"victor": {"age": 9}}]' ::jsonb
WHERE "name"='paul';
Giving:给予:
id ![]() |
data![]() |
name![]() |
|
---|---|---|---|
1 ![]() |
[{"jon": {"age": 4}}, {"jane": {"age": 7}}, {"beryl": {"age": 3}}, {"victor": {"age": 9}}] ![]() |
paul![]() |
|
I've tried using jsonb_insert in sqlalchemy, but I'm not clear on how to set the path.我试过在 sqlalchemy 中使用 jsonb_insert,但我不清楚如何设置路径。
I don't want to add the array at a particular key, but want to add to the existing array.我不想在特定键处添加数组,但想添加到现有数组中。
EDIT编辑
The following nests another array inside my existing one, ie in the form ['A', 'B']
becomes ['A','B',['C','D']]
.以下将另一个数组嵌套在我现有的数组中,即
['A', 'B']
的形式变为['A','B',['C','D']]
。 I want this to be ['A','B','C','D']
我希望这是
['A','B','C','D']
func.jsonb_insert(
cast(TestObj.data, JSONB), "{-1}", cast(new_records, JSONB), True
)
EDIT 2编辑 2
Using synchronize_session="fetch"
and adding the records in a loop works, but I'm not sure it would be very efficient for a lot of records.使用
synchronize_session="fetch"
并在循环中添加记录是可行的,但我不确定它对于很多记录是否非常有效。
Grateful for any ideas on how to improve this.感谢任何关于如何改进这一点的想法。
for rec in new_records:
session.query(TestObj).filter(TestObj.name == "paul").update(
{
"data": func.jsonb_insert(
cast(TestObj.data, JSONB), "{-1}", cast(rec, JSONB), True
)
},
synchronize_session="fetch",
)
Full example code:完整示例代码:
import os
from sqlalchemy.dialects.postgresql import JSON, JSONB
from sqlalchemy import func, cast
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import urllib
from sqlalchemy.dialects import postgresql
from dotenv import load_dotenv
load_dotenv()
user = urllib.parse.quote_plus(os.environ.get("DB_USER"))
passwd = urllib.parse.quote_plus(os.environ.get("DB_PW"))
DB_URL = "postgresql://{}:{}@{}:{}/{}".format(
user,
passwd,
os.environ.get("DB_HOST"),
os.environ.get("DB_PORT"),
os.environ.get("DB_NAME"),
)
engine = sa.create_engine(DB_URL)
Session = sessionmaker(bind=engine, autoflush=True)
session = Session()
Base = declarative_base()
class TestObj(Base):
__tablename__ = "test"
__table_args__ = {"autoload_with": engine, "schema": "public"}
initial_data = [
{
"jon": {"age": 4},
},
{"jane": {"age": 7}},
]
newentry = {"data": initial_data, "name": "paul"}
stmt = postgresql.insert(TestObj).values(newentry)
result = session.execute(stmt)
session.commit()
new_records = [{"bob": {"age": 10}}, {"billy": {"age": 10}}]
for rec in new_records:
session.query(TestObj).filter(TestObj.name == "paul").update(
{
"data": func.jsonb_insert(
cast(TestObj.data, JSONB), "{-1}", cast(rec, JSONB), True
)
},
synchronize_session="fetch",
)
session.commit()
In SQLAlchemy, the SQL ||
在 SQLAlchemy 中,SQL
||
operator is the Python +
operator.运算符是 Python
+
运算符。 I found this information in this Github issue .我在这个 Github issue中找到了这些信息。
Appending to the existing JSONB array of your example should be something like (untested):附加到您的示例的现有 JSONB 数组应该类似于(未经测试):
new_records = [{"bob": {"age": 10}}, {"billy": {"age": 10}}]
stmt = (
sa.update(TestObj)
.filter_by(name="paul")
.values(data=TestObj.data + new_records) # concatenate existing data with new records
)
session.execute(stmt)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.