postgresql 如何从json补丁更新db

j7dteeu8  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(1)|浏览(132)

我每隔几个小时就会收到一个复杂的json,其中一部分是一个Game对象,包含一个Player对象列表,每个Player都包含一个Training对象列表。(每个对象还有其他字段-int,字符串,字符串列表等)。如果Game对象在我的Postgres数据库中不存在,(我通过Game的id字段进行检查),我将整个结构插入到数据库中,每个对象作为其自己的表(Game的一个表,Player的一个表和Training的一个表)。下次我获取这个Game的json时,它已经存在于数据库中,所以我想更新它。我得到了旧的json,更新的json和json_patch。我想查询db,将其转换为json,并在json上应用补丁。问题是,(例如球员)与updated_object json中的列表排序方式不同。但我需要在db上工作,因为我需要有对象的主键,以便ORM知道哪些对象最新情况。最好的方法是什么?
型号:

class Game(Base):
    __tablename__ = "game"
    game_id: int = Column(INTEGER, primary_key=True,
                              server_default=Identity(always=True, start=1, increment=1, minvalue=1,
                                                      maxvalue=2147483647, cycle=False, cache=1),
                              autoincrement=True)
    unique_id: str = Column(TEXT, nullable=False)
    name: str = Column(TEXT, nullable=False)
    players = relationship('Player', back_populates='game')

class Player(Base):
    __tablename__ = "player"
    player_id: int = Column(INTEGER, primary_key=True,
                          server_default=Identity(always=True, start=1, increment=1, minvalue=1,
                                                  maxvalue=2147483647, cycle=False, cache=1),
                          autoincrement=True)
    unique_id: str = Column(TEXT, nullable=False)
    game_id: int = Column(INTEGER, ForeignKey('game.game_id'), nullable=False)
    name: str = Column(TEXT, nullable=False)
    birth_date = Column(DateTime, nullable=False)
    game = relationship('Game', back_populates='players')
    trainings = relationship('Training', back_populates='player')

class Training(Base):
    __tablename__ = "training"
    training_id: int = Column(INTEGER, primary_key=True,
                               server_default=Identity(always=True, start=1, increment=1, minvalue=1,
                                                       maxvalue=2147483647, cycle=False, cache=1),
                               autoincrement=True)
    unique_id: str = Column(TEXT, nullable=False)
    name: str = Column(TEXT, nullable=False)
    number_of_players: int = Column(INTEGER, nullable=False)
    player_id: int = Column(INTEGER, ForeignKey('player.player_id'), nullable=False)
    player = relationship('Player', back_populates='players')

字符串
JSON更新数据:

{"original_object":{"name":"Table Tennis","unique_id":"432","players":[{"unique_id":"793","name":"John","birth_date":"2023-10-28T00:10:56Z","trainings":[{"unique_id":"43","name":"Morning Session","number_of_players":3}, {"unique_id":"44","name":"Evening Session","number_of_players":2}]}]},"updated_object":{"name":"Table Tennis","unique_id":"432","players":[{"unique_id":"793","name":"John","birth_date":"2023-10-28T00:10:56Z","trainings":[{"unique_id":"43","name":"Morning Session","number_of_players":3}, {"unique_id":"44","name":"Evening Session","number_of_players":4}]}]},"json_patch":[{"op":"replace","path":"/players/0/trainings/1/numbre_of_players","value":4}],"timestamp":"2023-10-28T02:00:36Z"}


json_patch将第二次训练的'numbre_of_players'字段更新为值4。
添加新游戏的代码:

Session = sessionmaker(bind=engine_sync)
        session = Session()
        session.begin()
        game = Game.from_dict(json['updated_object'])
        existing_game = session.query(Game).filter_by(unique_id=game.id).first()
    if not existing_game:
        session.add(game)
        session.commit()


但是如果Game已经存在于数据库中,我不确定我应该做什么。

gcxthw6b

gcxthw6b1#

这看起来像是sqlalchemy.orm.Session.merge()的任务。您正在查看同一个Game的3种可能状态:
1.一个在数据库中,
1.一个在你的治疗中,
1.另一个,无论你从哪里得到这个更新的状态,
你想更新/覆盖前两个状态,假设第三个是真的。

Session = sessionmaker(bind=engine_sync)
session = Session()
session.begin()
game = Game.from_dict(json['updated_object'])
game = session.merge(game)
session.commit()

字符串
不需要检查它是否已经在你的会话和/或数据库中,因为merge()会自动检查,如果它没有找到匹配的Game,它会将其添加为一个新的。
Session.merge()检查源示例的主键属性,并尝试将其与会话中具有相同主键的示例进行协调。如果在本地找不到,则尝试根据主键从数据库加载对象,如果找不到,创建一个新示例。然后将源示例上的每个属性的状态复制到目标示例。然后返回结果目标示例通过该方法,原始源示例保持不变,并且如果尚未与Session相关联,则与Session解除关联。
请记住相应地设置级联,以处理可能与之相关的所有对象。

相关问题