I might not be understanding something, but for me there are two different concepts here:
map_obj = dbsession.query(Map).get(id_) is an object in memory, loaded with a long SELECT statement, allowing us to get and set different attributes and the session / transaction manager commits the auto-detected changes. Whereas with dbsession.query(Map).filter(Map.id == id_).update( {"screenshots": func.jsonb_set(Map.screenshots, '{size}', '"filename.jpg"')}, synchronize_session='fetch') there is no object in memory, what we are writing here is just a nicer syntax for a one line SQL UPDATE query. Even the triggered SELECT statement is just querying for a single .id, which we have anyway. Zsolt On 15 May 2017 at 17:29, mike bayer <mike...@zzzcomputing.com> wrote: > > > On 05/15/2017 10:54 AM, Zsolt Ero wrote: >> >> Thanks, it is all clear now. Just out of interest, what is the point >> of synchronize_session='fetch'? > > > that will do a SELECT and get the new value back and update your ORM object > in memory. Set synchronize_session=False if you don't care. > > > >> >> For me all it does is a simple SELECT maps.id AS maps_id FROM maps >> WHERE maps.id = %(id_1)s >> >> All I get as a return value is 0: not successful (probably id didn't >> exist), while 1: successful. It is the same behaviour both with >> 'fetch' and False. >> >> Zsolt >> >> On 15 May 2017 at 16:33, mike bayer <mike...@zzzcomputing.com> wrote: >>> >>> >>> >>> On 05/15/2017 10:31 AM, Zsolt Ero wrote: >>>> >>>> >>>> I'm trying to run your example, but it doesn't work: >>>> >>>> from sqlalchemy import func >>>> >>>> m = request.dbsession.query(models.Map).get(3) >>>> m.screenshots = func.jsonb_set(m.screenshots, '{key}', '"value"') >>>> request.dbsession.flush() >>>> >>>> It ends up in a (psycopg2.ProgrammingError) can't adapt type 'dict'. >>> >>> >>> >>> jsonb_set(models.Map.screenshots, ...) >>> >>> because this works against the column, not the value >>> >>> >>> >>> >>> >>>> >>>> Also, from the generated SQL it seems to me that it's also doing the >>>> full JSONB update from client side, not just inserting a key into the >>>> database server side. >>>> >>>> UPDATE maps SET screenshots=jsonb_set(%(jsonb_set_1)s, >>>> %(jsonb_set_2)s, %(jsonb_set_3)s) WHERE maps.id = %(maps_id)s >>>> {'maps_id': 3, 'jsonb_set_3': '"value"', 'jsonb_set_2': '{key}', >>>> 'jsonb_set_1': {u'small': u'2ad139ee69cdcd9e.jpg', u'full': >>>> u'68b3f51491ff1501.jpg'}} >>>> >>>> On 15 May 2017 at 16:18, Zsolt Ero <zsolt....@gmail.com> wrote: >>>>> >>>>> >>>>> Thanks for the answer. My use case is the following: >>>>> >>>>> I have an object (map_obj), which has screenshots in two sizes. I'm >>>>> using JSONB columns to store the screenshot filenames. >>>>> >>>>> Now, the two screenshot sizes are generated in parallel. The code is >>>>> like the following: >>>>> >>>>> map_obj = query(...by id...) >>>>> filename = generate_screenshot(size) # long running screenshot >>>>> generation >>>>> >>>>> try: >>>>> dbsession.refresh(map_obj, ['screenshots']) >>>>> map_obj.screenshots = dict(map_obj.screenshots, **{size: >>>>> filename}) >>>>> except Exception as e: >>>>> logger.warning(...) >>>>> >>>>> It worked well for 99.9% of the cases. The problem is that in the rare >>>>> case when both screenshots got rendered within a few milliseconds, one >>>>> of the screenshots got lost. >>>>> >>>>> The simple solution was to add lockmode='update' to the refresh, so >>>>> this way the refreshes are blocking until the other finishes the >>>>> update. >>>>> >>>>> But since this means locking a full row, I was thinking a simple JSONB >>>>> insertion would probably be better, since I can avoid locking the row. >>>>> >>>>> Zsolt >>>>> >>>>> >>>>> >>>>> >>>>> On 15 May 2017 at 15:58, mike bayer <mike...@zzzcomputing.com> wrote: >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> On 05/15/2017 09:32 AM, Zsolt Ero wrote: >>>>>>> >>>>>>> >>>>>>> >>>>>>> In PostgreSQL 9.5+ it is finally possible to modify a single key >>>>>>> inside >>>>>>> a >>>>>>> JSONB column. Usage is something like this: >>>>>>> >>>>>>> update maps set screenshots=jsonb_set(screenshots, '{key}', >>>>>>> '"value"') >>>>>>> where id = 10688 >>>>>>> >>>>>>> Is it possible to write this query using the ORM somehow? If not, >>>>>>> please >>>>>>> take it as a feature request. >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> You can use that function directly: >>>>>> >>>>>> my_object = session.query(Maps).get(5) >>>>>> >>>>>> my_object.screenshots = func.jsonb_set(my_object.screenshots, '{key}', >>>>>> '"value"') >>>>>> >>>>>> session.flush() >>>>>> >>>>>> >>>>>> as far as "transparent" ORM use of that, like this: >>>>>> >>>>>> my_object.screenshots[key] = "value" >>>>>> >>>>>> right now that is a mutation of the value, and assuming you were using >>>>>> MutableDict to detect this as an ORM change event, the ORM considers >>>>>> "screenshots" to be a single value that would be the target of an >>>>>> UPDATE, >>>>>> meaning the whole JSON dictionary is passed into the UPDATE. There is >>>>>> no >>>>>> infrastructure for the ORM to automatically turn certain column >>>>>> updates >>>>>> into >>>>>> finely-detailed SQL function calls. I can imagine that there might >>>>>> be >>>>>> some >>>>>> event-based way to make this happen transparently within the flush, >>>>>> however, >>>>>> but I'd need to spend some time poking around to work out how that >>>>>> might >>>>>> work. >>>>>> >>>>>> >>>>>> I'm not familiar with what the advantage to jsonb_set() would be and I >>>>>> can >>>>>> only guess it's some kind of performance advantage. I'd be curious >>>>>> to >>>>>> see >>>>>> under what scenarios being able to set one element of the JSON vs. >>>>>> UPDATEing >>>>>> the whole thing is a performance advantage significant compared to the >>>>>> usual >>>>>> overhead of the ORM flush process; that is, Postgresql is really fast, >>>>>> and >>>>>> for this optimization to be significant, you probably need to be >>>>>> calling >>>>>> the >>>>>> Core function directly anyway rather than going through the whole ORM >>>>>> flush >>>>>> process. But this is all based on my assumption as to what your goal >>>>>> of >>>>>> using this function is. >>>>>> >>>>>> >>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> 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 >>>>>>> <mailto:sqlalchemy+unsubscr...@googlegroups.com>. >>>>>>> To post to this group, send email to sqlalchemy@googlegroups.com >>>>>>> <mailto:sqlalchemy@googlegroups.com>. >>>>>>> Visit this group at https://groups.google.com/group/sqlalchemy. >>>>>>> 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 a topic in >>>>>> the >>>>>> Google Groups "sqlalchemy" group. >>>>>> To unsubscribe from this topic, visit >>>>>> https://groups.google.com/d/topic/sqlalchemy/hjjIyEC8KHQ/unsubscribe. >>>>>> To unsubscribe from this group and all its topics, 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. >>>>>> 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 a topic in >>> the >>> Google Groups "sqlalchemy" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/sqlalchemy/hjjIyEC8KHQ/unsubscribe. >>> To unsubscribe from this group and all its topics, 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. >>> 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 a topic in the > Google Groups "sqlalchemy" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/sqlalchemy/hjjIyEC8KHQ/unsubscribe. > To unsubscribe from this group and all its topics, 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. > 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. For more options, visit https://groups.google.com/d/optout.