简体   繁体   English

Postgres SQLAlchemy 附加到现有的 jsonb 记录

[英]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 ID data数据 name姓名
1 1 [{"jon": {"age": 4}}, {"jane": {"age": 7}}] [{“乔恩”:{“年龄”:4}},{“简”:{“年龄”:7}}] paul保罗
2 2 [{"beryl": {"age": 3}}, {"victor": {"age": 9}}] [{“绿柱石”:{“年龄”:3}},{“维克多”:{“年龄”: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 ID data数据 name姓名
1 1 [{"jon": {"age": 4}}, {"jane": {"age": 7}}, {"beryl": {"age": 3}}, {"victor": {"age": 9}}] [{“乔恩”:{“年龄”:4}},{“简”:{“年龄”:7}},{“绿柱石”:{“年龄”:3}},{“维克多”:{“年龄”: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.

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