简体   繁体   中英

sqlalchemy: "syncing" jsonb column between parent and child tables

Suppose we have two sqlalchemy classes

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.dialects.postgresql import JSONB


db = SQLAlchemy()

class Parent(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    data = db.Column(JSONB)

class Child(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, db.ForeignKey("parent.id"))
    parent = db.relationship(Parent, backref="children")
    data = db.Column(JSONB)

The content of Child.data is a dictionary d and the content of Parent.data is a list of dictionaries, one for each child, ie parent.data = [child.data for child in parent.children] .

Is there a way to keep the two data columns in sync?


In principle one could eg get rid of the Parent.data column and replace it with a property that simply returns [child.data for child in parent.children] . However, in our use case this is quite slow so we'd like to keep a copy of the aggregated data in the Parent.data column. Moreover, some parts of the application modify the whole Parent.data at once, while others modify Child.data . I thought about making data "private" and write a setter that automatically updates the corresponding column in the other table (maybe checking if it's changed before updating, in order to avoid ending up in an infinite loop). Is there a better way?

Thanks :)

You probably want to use event listeners. Something like the below should do it, depending on how your json is structured

import sqlalchemy as sa
@sa.event.listens_for(Parent.data, "modified")
def _parent_data_modified(parent, data, initiator):
    for child in parent.children:
        # adjust for your data structure
        child.data = data[child.id]

@sa.event.listens_for(Child.data, "modified")
def _child_data_modified(child, data, initiator):
    old_data = parent.data.copy()
    old_data[child.id] = data
    parent.data = old_data

https://docs.sqlalchemy.org/en/13/orm/extensions/mutable.html#receiving-events

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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