pythonpostgresqljsonbasyncpg

python+asyncpg+PostgreSQL returns jsonb column as a string instead of an object


I'm new to python and just came to a problem: i've set up a simple program to fetch some data from PostgreSQL database. They say that asyncpg library automatically converts JSONB data to Python objects (dicts/lists) by default. This doesn't happen in my case when I select data from a table. I've made synthetic example to demonstrate this:

import asyncio
import asyncpg

async def main():
    conn = await asyncpg.connect("postgres://user:pass@localhost/database")
    res = await conn.fetch("select '[1, 2, 3]'::jsonb as column;")
    for row in res:
        for key, value in row.items():
            print("'" + key + "'")
            print("'" + value + "'")
# Call main
if __name__ == "__main__":
    asyncio.run(main())

and the output is

'column'
'[1, 2, 3]'

Using debugger, I can see that value is a string as well. How can I fix that?


Solution

  • To automatically decode jsonb values to Python objects with asyncpg, you need to explicitly register a custom type codec:

    import asyncio
    import asyncpg
    import json
    
    async def main():
        conn = await asyncpg.connect("postgres://user:pass@localhost/database")
    
        await conn.set_type_codec(
            'jsonb',
            encoder=json.dumps,
            decoder=json.loads,
            schema='pg_catalog'
        )
    
        res = await conn.fetch("select '[1, 2, 3]'::jsonb as column;")
        for row in res:
            print(row['column'], type(row['column']))  # Output: [1, 2, 3] <class 'list'>
    
        await conn.close()
    
    asyncio.run(main())