On Fri, Jun 14, 2019, at 12:46 PM, Mike Bayer wrote: > > > On Fri, Jun 14, 2019, at 12:22 PM, João Miguel Neves wrote: >> Not performance, actually to avoid a race condition with key/values written >> to JSONB fields. Ended up with the following function that we use for when >> multiple updates at the same time can occur (from the frontend mostly). It's >> based on your recommendations from >> https://groups.google.com/forum/#!topic/sqlalchemy/hjjIyEC8KHQ >> >> When we got 2 requests in parallel (one updating key1 with value1 and >> another updating key2 with value2), the first would write value1, but as the >> second had loaded the JSONB field before, it would write to key2 and then >> save the whole content of the JSONB field without the update to key1 >> effectively losing data in our case. >> >> def atomic_jsonb_set(context, dynamic_column_name, column_id, value): >> id_key = [col.name for col in inspect(context.__class__).primary_key] >> identifier = {key: getattr(context, key) for key in id_key} >> >> DBSession.query(context.__class__).filter_by(**identifier).update( >> { >> dynamic_column_name: func.jsonb_set( >> getattr(context.__class__, dynamic_column_name), >> f"{{{column_id}}}", >> config["sqlalchemy.json_serializer"](value), >> ) >> }, >> synchronize_session="fetch", >> ) > > > OK so the patterns you can use with that are the versioning column, or if you > want the UPDATE to be atomic there might be complications if you are updating > columns in both "person" and "engineer". I might use SELECT..FOR UPDATE for a > pessimistic approach.
oh and by versioning column i mean https://docs.sqlalchemy.org/en/13/orm/versioning.html?highlight=versioning, which is also using regular Session.add() types of patterns, not query.update(). > > > >> >> On Fri, Jun 14, 2019 at 5:07 PM Mike Bayer <mike...@zzzcomputing.com> wrote: >>> __ >>> >>> >>> On Fri, Jun 14, 2019, at 11:49 AM, João Miguel Neves wrote: >>>> Hi Mike, >>>> >>>> Thank you very much for the quick response! >>>> >>>> Is there any other way to find the right table from the model other than >>>> somthing like Engineer.name.property.columns[0].table? (I'm trying to do >>>> an update in a codepath that can have several different models passed to >>>> it) >>> >>> >>> you're doing query.update() for performance reasons, right? yeah you >>> probably have to do something like that, or just use regular session >>> patterns to update data. >>> >>> >>> >>>> >>>> TIA, >>>> João >>>> >>>> On Fri, Jun 14, 2019 at 4:04 PM Mike Bayer <mike...@zzzcomputing.com> >>>> wrote: >>>>> __ >>>>> >>>>> >>>>> On Fri, Jun 14, 2019, at 10:30 AM, João Miguel Neves wrote: >>>>>> Hi, >>>>>> >>>>>> I have a situation where an update tries to update the wrong table on >>>>>> when a column comes from the parent table and is not on the current >>>>>> table. I'll grant I didn't quite understand all the caveats in >>>>>> https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.update >>>>>> so let me apologise if it's written there - then I just need a pointer >>>>>> in the right direction. Here is some sample code (mostly adapted from >>>>>> https://stackoverflow.com/questions/44183500/problems-with-update-and-table-inheritance-with-sqlalchemy >>>>>> - the code won't work on sqlite). >>>>> >>>>> >>>>> Hi there - >>>>> >>>>> yes the caveats refer to the joined inheritance situation as where there >>>>> are intricacies here. >>>>> >>>>> Your UPDATE statement refers to the "name" column which is part of >>>>> People, so you need to format your UPDATE statement in terms of the >>>>> "people" table, which means the second query is not supported. It at >>>>> least has to be against "People" otherwise the UPDATE is only targeting >>>>> the "engineer" table. >>>>> >>>>> if you want to limit the "name" updates to only those rows that are >>>>> Engineer, use the discriminator column to filter to People.type == >>>>> "engineer". >>>>> >>>>> >>>>> >>>>>> >>>>>> zi >>>>>> ---- >>>>>> >>>>>> The error message is: >>>>>> >>>>>> Traceback (most recent call last): >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 1244, in _execute_context >>>>>> cursor, statement, parameters, context >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/default.py", >>>>>> line 550, in do_execute >>>>>> cursor.execute(statement, parameters) >>>>>> psycopg2.errors.UndefinedColumn: column "name" of relation "engineer" >>>>>> does not exist >>>>>> LINE 1: UPDATE engineer SET name='Mary', updated=now() FROM people W... >>>>>> ^ >>>>>> >>>>>> >>>>>> The above exception was the direct cause of the following exception: >>>>>> >>>>>> Traceback (most recent call last): >>>>>> File "update-inheritance.py", line 63, in <module> >>>>>> Engineer.name == 'James', ).update({Engineer.name: 'Mary'}) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/orm/query.py", >>>>>> line 3824, in update >>>>>> update_op.exec_() >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", >>>>>> line 1673, in exec_ >>>>>> self._do_exec() >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", >>>>>> line 1866, in _do_exec >>>>>> self._execute_stmt(update_stmt) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/orm/persistence.py", >>>>>> line 1678, in _execute_stmt >>>>>> self.result = self.query._execute_crud(stmt, self.mapper) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/orm/query.py", >>>>>> line 3356, in _execute_crud >>>>>> return conn.execute(stmt, self._params) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 988, in execute >>>>>> return meth(self, multiparams, params) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/sql/elements.py", >>>>>> line 287, in _execute_on_connection >>>>>> return connection._execute_clauseelement(self, multiparams, params) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 1107, in _execute_clauseelement >>>>>> distilled_params, >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 1248, in _execute_context >>>>>> e, statement, parameters, cursor, context >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 1466, in _handle_dbapi_exception >>>>>> util.raise_from_cause(sqlalchemy_exception, exc_info) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/util/compat.py", >>>>>> line 383, in raise_from_cause >>>>>> reraise(type(exception), exception, tb=exc_tb, cause=cause) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/util/compat.py", >>>>>> line 128, in reraise >>>>>> raise value.with_traceback(tb) >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/base.py", >>>>>> line 1244, in _execute_context >>>>>> cursor, statement, parameters, context >>>>>> File >>>>>> "/home/joao/testes/sa-bugs/.ve/lib/python3.6/site-packages/sqlalchemy/engine/default.py", >>>>>> line 550, in do_execute >>>>>> cursor.execute(statement, parameters) >>>>>> sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedColumn) >>>>>> column "name" of relation "engineer" does not exist >>>>>> LINE 1: UPDATE engineer SET name='Mary', updated=now() FROM people W... >>>>>> ^ >>>>>> >>>>>> [SQL: UPDATE engineer SET name=%(people_name)s, updated=now() FROM >>>>>> people WHERE engineer.id = people.id AND people.name = %(name_1)s] >>>>>> [parameters: {'people_name': 'Mary', 'name_1': 'James'}] >>>>>> (Background on this error at: http://sqlalche.me/e/f405) >>>>>> I can get the correct table to update through: >>>>>> >>>>>> table = Engineer.name.property.columns[0].table >>>>>> >>>>>> And the following update works (albeit with a slightly different >>>>>> semantics): >>>>>> >>>>>> update(table).where(table.c.name == 'James').values({table.c.name : >>>>>> 'Mary'}) >>>>>> From what I've read, adding the People.id == Engineer.id should be >>>>>> enough, but it seems like I missed some detail. Can you help? >>>>>> >>>>>> Thanks in advance for any help/pointers, >>>>>> João >>>>>> >>>>>> >>>>>> -- >>>>>> SQLAlchemy - >>>>>> The Python SQL Toolkit and Object Relational Mapper >>>>>> >>>>>> http://www.sqlalchemy.org/ >>>>>> >>>>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>>>> description. >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "sqlalchemy" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>> an email to sqlalchemy+unsubscr...@googlegroups.com. >>>>>> To post to this group, send email to sqlalchemy@googlegroups.com. >>>>>> Visit this group at https://groups.google.com/group/sqlalchemy. >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/sqlalchemy/4b8377e7-3fff-4750-aebf-aaa5eaac35da%40googlegroups.com >>>>>> >>>>>> <https://groups.google.com/d/msgid/sqlalchemy/4b8377e7-3fff-4750-aebf-aaa5eaac35da%40googlegroups.com?utm_medium=email&utm_source=footer>. >>>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>>> >>>>> -- >>>>> SQLAlchemy - >>>>> The Python SQL Toolkit and Object Relational Mapper >>>>> >>>>> http://www.sqlalchemy.org/ >>>>> >>>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>>> description. >>>>> --- >>>>> You received this message because you are subscribed to the Google Groups >>>>> "sqlalchemy" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send an >>>>> email to sqlalchemy+unsubscr...@googlegroups.com. >>>>> To post to this group, send email to sqlalchemy@googlegroups.com. >>>>> Visit this group at https://groups.google.com/group/sqlalchemy. >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/sqlalchemy/085a157e-cda0-478a-b4a8-04903d69b780%40www.fastmail.com >>>>> >>>>> <https://groups.google.com/d/msgid/sqlalchemy/085a157e-cda0-478a-b4a8-04903d69b780%40www.fastmail.com?utm_medium=email&utm_source=footer>. >>>>> For more options, visit https://groups.google.com/d/optout. >>>> >>>> -- >>>> SQLAlchemy - >>>> The Python SQL Toolkit and Object Relational Mapper >>>> >>>> http://www.sqlalchemy.org/ >>>> >>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>> description. >>>> --- >>>> You received this message because you are subscribed to the Google Groups >>>> "sqlalchemy" group. >>>> To unsubscribe from this group and stop receiving emails from it, send an >>>> email to sqlalchemy+unsubscr...@googlegroups.com. >>>> To post to this group, send email to sqlalchemy@googlegroups.com. >>>> Visit this group at https://groups.google.com/group/sqlalchemy. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/sqlalchemy/CAJGrhWYeQFCpOiwbtToqnVTq8qy%2Bya3V7NUmmotY7%2Ber-0xYvg%40mail.gmail.com >>>> >>>> <https://groups.google.com/d/msgid/sqlalchemy/CAJGrhWYeQFCpOiwbtToqnVTq8qy%2Bya3V7NUmmotY7%2Ber-0xYvg%40mail.gmail.com?utm_medium=email&utm_source=footer>. >>>> For more options, visit https://groups.google.com/d/optout. >>> >>> >>> -- >>> SQLAlchemy - >>> The Python SQL Toolkit and Object Relational Mapper >>> >>> http://www.sqlalchemy.org/ >>> >>> To post example code, please provide an MCVE: Minimal, Complete, and >>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>> description. >>> --- >>> You received this message because you are subscribed to the Google Groups >>> "sqlalchemy" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to sqlalchemy+unsubscr...@googlegroups.com. >>> To post to this group, send email to sqlalchemy@googlegroups.com. >>> Visit this group at https://groups.google.com/group/sqlalchemy. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/sqlalchemy/27f24134-661e-4c16-982a-6983a82609a4%40www.fastmail.com >>> >>> <https://groups.google.com/d/msgid/sqlalchemy/27f24134-661e-4c16-982a-6983a82609a4%40www.fastmail.com?utm_medium=email&utm_source=footer>. >>> For more options, visit https://groups.google.com/d/optout. >> >> -- >> SQLAlchemy - >> The Python SQL Toolkit and Object Relational Mapper >> >> http://www.sqlalchemy.org/ >> >> To post example code, please provide an MCVE: Minimal, Complete, and >> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >> description. >> --- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to sqlalchemy+unsubscr...@googlegroups.com. >> To post to this group, send email to sqlalchemy@googlegroups.com. >> Visit this group at https://groups.google.com/group/sqlalchemy. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/sqlalchemy/CAJGrhWZ_REpV09w5YVz-oY4BoTQjuB2DqTUirwwd8sAweKuHMg%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/sqlalchemy/CAJGrhWZ_REpV09w5YVz-oY4BoTQjuB2DqTUirwwd8sAweKuHMg%40mail.gmail.com?utm_medium=email&utm_source=footer>. >> For more options, visit https://groups.google.com/d/optout. > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/b743f771-12db-4635-bc2e-5d44ec140ac5%40www.fastmail.com > > <https://groups.google.com/d/msgid/sqlalchemy/b743f771-12db-4635-bc2e-5d44ec140ac5%40www.fastmail.com?utm_medium=email&utm_source=footer>. > For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/0a138c5b-992a-4410-876b-32351a57d2fb%40www.fastmail.com. For more options, visit https://groups.google.com/d/optout.